Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Name conflict between template struct and template member function

In the following, GCC confuses template struct name with template member function name of class A, while Clang compiles fine (live example):

template<typename T>
struct name {};

struct A
{
    template<bool B>
    void name() { }
};

template<bool B, typename T>
void f(T& x) { x.template name<B>(); }

Function f is apparently meant to be called with an argument of type A in this example, but it could be anything else, so f needs to remain a template function.

I don't care much which compiler is correct, I only need a work-around because I really don't know any syntax other than

x.template name<B>();

to call the member function, and I cannot see how a using declaration or any other way of disambiguation could apply.

EDIT Yes, I now tried the more explicit syntax

x.T::template name<B>();

which works, but is really ugly. Any way to make the brief syntax work? Otherwise, it might be preferable to change one of the two names to begin with...

EDIT2 My original version of f works on a universal reference T&&, which needs the ugliest

using X = typename std::remove_reference<T>::type;
x.X::template name<B>();

in case T is a reference... And all this for a simple function call.

like image 746
iavr Avatar asked Mar 11 '14 00:03

iavr


1 Answers

I've thought about this a bit and I can't see any way to make the most basic syntax you want work, due to all the templates involved. The reason you have to specify template is because otherwise it looks to the compiler like you are using < to compare the address of the function to B.

As you said, you could simply rename one of the name identifiers, allowing the compiler to have no ambiguity as to which one you mean.

Alternately you could do exactly what you said and fully qualify the call. I don't find this to be ugly syntax: it's perfectly clear to the reader exactly what's going on, and after all you only have to write the function one time.

template<bool B, typename T>
void f(T& x)
{
    typedef typename std::remove_reference<T>::type callee;

    x.callee::template name<B>();
}

Finally if you could elaborate a little more on the real problem you're trying to solve with this template we might be able to offer an orthogonal solution that doesn't involve such type aliasing at all.

like image 87
Mark B Avatar answered Oct 21 '22 14:10

Mark B