0

I'm observing some seemingly strange behavior when trying to instantiate a template function.

In brief, I'm implementing a template function library. For the purposes of this library, I am assuming that for each type T used to instantiate one of these templates, the user of this library will have implemented a function with a specific signature, say:

void foo(const T& t)

I would like to define my library template functions within an enclosing namespace, say A. Similarly, I would like these functions to be usable within another (user-defined) namespace, say B. The overall usage pattern I have in mind is the following:

    #include <string>
    #include <iostream>

    // My library function
    namespace A {

    template <typename T>
    void my_library_function(const T& t) { foo(t); }

    }


    // Intended usage
    namespace B {

    // User writes a function foo(T) for the specific type T they want 
    // to use in conjunction with my_library_function()
    void foo(const std::string&  s) { std::cout << s << std::endl; }

    // User can then use my_library_function() in their own code
    void super_cool_user_function(const std::string& s) { A::my_library_function<std::string>(s); }
    }

    int main()
    {
        std::string s = "Hello world!";
        B::super_cool_user_function(s);
    }

I would expect this to work, since in this code my_library_function() is only used within the same namespace B where foo(std::string& s) is defined. However, when trying to compile this, I get the following error:

> In instantiation of ‘void A::my_library_function(const T&) [with T =std::__cxx11::basic_string<char>]’:
>
> example.cpp:8:43: error: ‘foo’ was not declared in this scope
>
> void my_library_function(const T& t) { foo(t); }
>
>example.cpp:8:43: note: suggested alternative:
>
>example.cpp:17:6: note:   ‘B::foo’
>
>void foo(const std::string&  s) { std::cout << s << std::endl; }

So, I have two (hopefully straightforward?) questions:

  • Why is this error occurring?

  • Is there a clean way of modifying my approach (the implementation of the template) to enable the intended usage shown above?

Thanks!

con ko
  • 1,368
  • 5
  • 18
  • 1
    `B::foo` is not visible from inside `A` namespace, where you attempt to call it. Moreover, it's not even declared at the point where the template is defined. It can only be found via argument-dependent lookup at the point of instantiation, but the argument type, `std::string`, is not associated with `B` namespace either. It's unclear why you expect this to work. – Igor Tandetnik Apr 19 '20 at 01:06
  • Suppose that you have a `C` namespace, which has `foo` as well. If your code worked, how would `A::my_library_function` know, which `foo` to call? `B::foo` or `C::foo`? If you want to call `foo` unqualified in that template function, then you need to add some parameter to `foo`, whose type has a relation to `foo`'s namespace, so `foo` can be looked up by ADL. – geza Apr 19 '20 at 01:41
  • Looking at your example in a vacuum, the only way you could get this to work is to `prototype` the `foo` function prior to its usage. The functionality you specifically want, is not possible. – WBuck Apr 19 '20 at 01:42
  • Thanks for your quick replies everyone. @geza: For ADL, would it suffice to introduce a typedef for std::string that is defined in the B namespace ( for example `typedef std::string MyString` ) and then replace `std::string` with `MyString` throughout? @WBuck: Could you elaborate what your prototyping suggestion would look like? (Apologies if I'm being somewhat dense here ... ) – David Rosen Apr 19 '20 at 23:26
  • @DavidRosen: no, it won't work. A typedef is not a new type, it's just an alias. – geza Apr 19 '20 at 23:48

0 Answers0