Search code examples
c++templatesc++17friend

friend, template, namespace


I want to have a templated friend function. However, I do not know how to make it works in the same way for no templated function. Here is a sample code

#include <iostream>

namespace ns{
struct Obj {
    friend void foo(Obj){std::cout << "no problem" << std::endl;}

    template<typename T>
    friend void bar(Obj){std::cout << "problem" << std::endl;}
};
}

int main() {
    ns::Obj obj;
    foo(obj); // Compile
    bar<int>(obj); // Not compile
    return 0;
}

Solution

  • Before C++20, you need to teach the compiler that bar is the name of a template so that it knows that < starts a template argument list and is not the less-than operator:

    template<char> void bar() = delete;
    
    int main() {
        ns::Obj obj;
        foo(obj); // Compile
        bar<int>(obj); // Now compiles too
        return 0;
    }
    

    Note that all the bar overload has to do is to be a function template. The signature doesn't matter as long as it's not so good as to interfere with the overload resolution; () is a good choice because by definition we are passing at least one argument, so a function template taking no parameters can never be viable.

    Alternatively, you can redesign bar to deduce T from a tag argument:

    template<class T>
    struct type {};
    
    namespace ns{
    struct Obj {    
        // ...
    
        template<typename T>
        friend void bar(Obj, type<T>) { /* ... */ }
    };
    }
    // ...
    
    bar(obj, type<int>()); // OK
    

    In C++20, the compiler will assume that bar names a template when it sees the < and name lookup finds nothing, so your code will just work.