CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16
  1. #1
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347

    Using a template function as for_each "argument" = unresolved external symbol error

    Hello,

    I tried to make the subject intuitive. Anyway, as described, I'm
    trying to use a template function as the function argument for
    for_each(). In particular, I'm trying to use boost's checked_delete
    in an attempt to basically delete every member in a vector of
    pointers [who each point to dynamically allocated memory].

    Yeah, I know I could just do a loop and delete each one explicitly,
    but I was kind of wanting to save a little space

    Anyway, I'm getting an "unresolved external symbol" error ... and
    rightly so. Just telling for_each() to CALL this template function
    doesn't actually instantiate it. I've found that to use this function
    as a functor, I have to do something like this first [for every
    type that I want to use checked_delete with]:
    Code:
    checked_delete<SomeType>(0);
    This will instantiate the proper function and everything works
    great [albeit with one additional line of code].

    So, my question: is there a better way to achieve my goal of using
    a template function as a function argument to for_each()?
    Here's basically what my for_each line is:
    Code:
    for_each(container.begin(), container.end(), boost::checked_delete<SomeType>);
    If you're not familiar with boost, checked_delete is a "safer"
    delete. The only reason I'm using it is that it won't really cost me
    anything ... and it's an existing function that'll delete for me so
    I don't need to write my own....

    Thank you for your time.

    --Paul

  2. #2
    Join Date
    Jun 2001
    Location
    Switzerland
    Posts
    4,443
    Make a functor out of it
    Code:
    template <typename T>
    class checked_delete
    {
    public:
        void operator(T *t){boost::checked_delete<T>(t);}
    };
    //.....
    for_each(container.begin(), container.end(), checked_delete<SomeType>() );
    //note -- I didn't compile this code
    Gabriel, CodeGuru moderator

    Forever trusting who we are
    And nothing else matters
    - Metallica

    Learn about the advantages of std::vector.

  3. #3
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347
    Thank you for the input. I definitely did consider that approach,
    but I would just use delete for it I was hoping to reuse boost's
    current function so that I wouldn't have to make ANY functor
    myself; I was hoping that there would be a ... easier way than
    creating a separate functor for it. I never bothered saying that,
    of course, so how would anyone know?

    Unless someone knows something better, I probably WILL use
    your approach; actually I already have a Deleter functor ... but I
    was hoping to use some existing code so that I could throw
    Deleter away

    Thanks again for your time.

    --Paul

  4. #4
    Join Date
    Sep 2002
    Posts
    1,747

    interesting...

    I haven't had any instantiation problem with parametrized functions before, so I tossed together this quick little program.
    Code:
    #include <iostream>
    using std::cout;
    
    template <typename SomeType>
    void Function(SomeType someInstance)
    {
      cout << "In the parametrized function!\n";
    }
    
    template <typename SomeType>
    class SomeClass
    {
      SomeType member_;
    public:
      SomeClass(SomeType someInstance) : member_(someInstance)
      {
      }
    
      void SomeMethod(void (*functionPointer)(SomeType))
      {
        cout << "In the calling method!\n";
        functionPointer(member_);
      }
    };
    
    int main()
    {
      SomeClass<int> intClass(666);
      intClass.SomeMethod(Function<int>);
    
      return 0;
    }
    It compiles and runs as expected on MSVC++ 6.0 (sp5), so I'm curious what the problem here is.... I don't need to put the Function<int> anywhere else to instantiate it properly, and I think this simulates the same logic. Have I done anything weirdly different than the original problem here?
    */*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

    "It's hard to believe in something you don't understand." -- the sidhi X-files episode

    galathaea: prankster, fablist, magician, liar

  5. #5
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347

    Wink

    Thank you, galathea. I always give people advice by telling them
    to create a "stub" program so that others can work with it; I
    neglected to do that on my own. However, we're doing slightly
    different things.

    I removed SomeClass; try this code:

    Code:
    template <typename SomeType>
    void Function(SomeType someInstance)
    {
      cout << "In the parametrized function!\n";
    }
    
    int main()
    {
      //SomeClass<int> intClass(666);
      //intClass.SomeMethod(Function<int> );
      
      vector<int> classes;
      for_each(classes.begin(), classes.end(), Function<int>);
    
      return 0;
    }
    My compiler is Visual Studio .NET and I'm getting:
    tester error LNK2019: unresolved external symbol "void __cdecl
    Function(int)" (?Function@@YAXH@Z) referenced in function _main
    I'm going to go try it on Visual Studio 6.0 SP5 and see if I get
    the same results. I think I'm going to wind up going the functor
    route :P

    --Paul

    Edit: Oh, it should be noted that if I put the following line in my
    program, the function is instantiated and everything works fine.
    Could it be that my implementation of for_each is messed up?
    I will also go try this on gcc.
    Code:
    Function<int>(0);
    Last edited by PaulWendt; February 26th, 2003 at 05:14 PM.

  6. #6
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347
    Alright, well the code doesn't work with Visual Studio 6.0 either.
    I tried it on gcc, however, and everything worked fine there.
    I'm assuming, then, that it's a problem with Microsoft's compiler
    but I'm going to try e-mailing the comeau compiler to see what
    they come up with [I only have the two aforementioned
    compilers]

    I really should have tried this on gcc first, though. It's so good
    with everything else that I just [mistakenly] assume that it's my
    code that's wrong and not the compiler while working with
    Visual Studio C++ 7.0

    --Paul
    Last edited by PaulWendt; February 26th, 2003 at 05:27 PM.

  7. #7
    Join Date
    Apr 1999
    Location
    Altrincham, England
    Posts
    4,470
    It's possible that 6.0 is wrong and 7.0 is correct - I wouldn't like to say for sure. Have you tried galathea's example on VC++ 7.0? I can point to a difference between the two, though: in your example, the templated function that's passed as an argument is typed through a template parameter of for_each, whereas in galathea's example the function argument is not further "templatised". This may or may not be relevant (it could be utter twaddle on my part), but I just thought I'd mention it.
    Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
    --
    Sutter and Alexandrescu, C++ Coding Standards

    Programs must be written for people to read, and only incidentally for machines to execute.

    --
    Harold Abelson and Gerald Jay Sussman

    The cheapest, fastest and most reliable components of a computer system are those that aren't there.
    -- Gordon Bell


  8. #8
    Join Date
    Sep 2002
    Posts
    1,747

    hmmm

    You are absolutely right, Graham, that the two things aren't the same logic. I didn't catch that difference before, so I wrote up
    Code:
    #include <iostream>
    using std::cout;
    
    template <typename SomeType>
    void Function(SomeType someInstance)
    {
      cout << "In the parametrized function!\n";
    }
    
    template <typename SomeType>
    class SomeClass
    {
      SomeType member_;
    public:
      SomeClass(SomeType someInstance) : member_(someInstance)
      {
      }
    
      void SomeMethod(void (*functionPointer)(SomeType))
      {
        cout << "In the calling method!\n";
        functionPointer(member_);
      }
    };
    
    template <typename SomeType, class Functor>
    void CallerFunction (SomeType someInstance, Functor someFunctor)
    {
      cout << "In the calling function!\n";
      someFunctor(someInstance);
    }
    
    int main()
    {
      // method of parametrized class
      SomeClass<int> intClass(666);
      intClass.SomeMethod(Function<int>);
    
      // parametrized function call
      CallerFunction(666, Function<int>);
    
      return 0;
    }
    and it also compiled and ran as expected!?! I was curious because when I realized the difference, I thought that might be the cause. Now, however, I am stumped and can only expect it to be some inability with the compiler and the for_each specification, but I don't see anything too off with the for_each definition that would cause it...
    */*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

    "It's hard to believe in something you don't understand." -- the sidhi X-files episode

    galathaea: prankster, fablist, magician, liar

  9. #9
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347
    Originally posted by Graham
    It's possible that 6.0 is wrong and 7.0 is correct - I wouldn't like to say for sure. Have you tried galathea's example on VC++ 7.0? I can point to a difference between the two, though: in your example, the templated function that's passed as an argument is typed through a template parameter of for_each, whereas in galathea's example the function argument is not further "templatised". This may or may not be relevant (it could be utter twaddle on my part), but I just thought I'd mention it.
    Thanks a lot for your reply. I had some incremental posts along
    the way, but as it turns out, the code works on neither Visual
    Studio 6.0 nor Visual Studio 7.0. The code DOES compile and
    link properly on gcc-3.1. I went to try Comeau's compiler on the
    web, only to find out that they do no linking

    So, my bet is that it's a Visual Studio problem ... but I have a
    workaround for now. I will investigate the differences between
    galathea's code and my code more strictly, however; thank you
    for pointing out the differences.

    --Paul

  10. #10
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347

    Re: hmmm

    Originally posted by galathaea
    Now, however, I am stumped and can only expect it to be some inability with the compiler and the for_each specification, but I don't see anything too off with the for_each definition that would cause it...
    I didn't try this, but I might look at STLPort and see if their
    for_each has this same problem? It's just a thought. Thank you
    all for your wonderful and helpful replies

    --Paul

  11. #11
    Join Date
    Jul 2003
    Posts
    3

    VS.NET 2003 works

    The code links in 2003. I remember reading that MS fixed a lot of template issues in this release. It may be worth upgrading if you use a lot of templates.

    Derek

  12. #12
    Join Date
    Dec 2001
    Location
    Ontario, Canada
    Posts
    2,236
    It appears to be a template bug, since this code compiles and links:

    Code:
      void(* pFn)(int) = Function<int>;
      std::for_each( classes.begin(), classes.end(), pFn );

  13. #13
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588

    Re: VS.NET 2003 works

    Originally posted by Derek_Burdick
    The code links in 2003. I remember reading that MS fixed a lot of template issues in this release. It may be worth upgrading if you use a lot of templates.

    Derek
    Yes, confirmed, it works fine in 2003.

    It could also be a problem with the for_each implementation in Dinkumware's STL, but I don't see exactly what could be happening.

    I'll try it tomorrow with STLPort.

    [Edit: doesn't work with STLPort on VC6 either. So it must be a compiler bug.]
    Last edited by Yves M; August 26th, 2003 at 08:03 AM.
    Get this small utility to do basic syntax highlighting in vBulletin forums (like Codeguru) easily.
    Supports C++ and VB out of the box, but can be configured for other languages.

  14. #14
    Join Date
    Dec 2001
    Location
    Ontario, Canada
    Posts
    2,236
    I think it is because the compiler doesn't know it is a function pointer? For example, it foreach was defined as:

    template<class fIt, class T, class U>
    void foreach( fIt beg, fIt end, T (* fn)(U& u) );

    i bet it would work.

  15. #15
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588
    That would mean that the unary function needs to have exactly that calling convention and e.g. a function not taking a reference would not qualify for foreach.
    Get this small utility to do basic syntax highlighting in vBulletin forums (like Codeguru) easily.
    Supports C++ and VB out of the box, but can be configured for other languages.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured