Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;
}
like image 517
Antoine Morrier Avatar asked Dec 13 '22 16:12

Antoine Morrier


1 Answers

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.

like image 63
T.C. Avatar answered Dec 25 '22 22:12

T.C.