下面,GCC混淆了模板结构体name
和A
类的模板成员函数name
,而Clang编译得很好(实例):
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>(); }
在这个例子中,函数f
显然是用A
类型的参数来调用的,但它可以是其他任何东西,所以f
需要保持为模板函数。
我不太关心哪个编译器是正确的,我只需要一个变通方法,因为除了
我真的不知道任何语法x.template name<B>();
来调用成员函数,我看不出using
声明或任何其他消歧方式如何适用。
EDIT是的,我现在尝试了更显式的语法
x.T::template name<B>();
可以工作,但是真的很丑。有什么办法使简短的语法工作吗?否则,最好将两个名称中的一个改为以…
开头。EDIT2我的原始版本f
工作在通用引用T&&
上,它需要最丑的
using X = typename std::remove_reference<T>::type;
x.X::template name<B>();
的情况下T
是一个引用…这一切都是为了一个简单的函数调用。
我想了一下,由于所有涉及的模板,我看不到任何方法可以使你想要的最基本的语法工作。您必须指定template
的原因是,否则编译器会认为您正在使用<
来比较函数的地址和B
。
就像你说的,你可以简单地重命名一个name
标识符,允许编译器对你指的是哪一个没有歧义。
或者你可以完全按照你说的做,并完全限定调用。我不认为这是丑陋的语法:对于读者来说,完全清楚发生了什么,毕竟您只需要编写一次函数。
template<bool B, typename T>
void f(T& x)
{
typedef typename std::remove_reference<T>::type callee;
x.callee::template name<B>();
}
最后,如果你能更详细地说明你试图用这个模板解决的实际问题,我们可能能够提供一个正交解决方案,根本不涉及这种类型混叠
编辑:正如Constructor和iavr指出的,以下是非标准行为:
与VS2013的以下工作:
template<typename T>
struct name {};
struct A
{
template<bool B>
void name() {
std::cout << "A::name() called with B=" << B<< std::endl;
}
};
template<bool B, typename T>
void f(T& x) { x.name<B>(); }
int main(){
A a;
f<true>(a);
}
输出: A::name() called with B=1
您也可以使用命名空间。
将"结构名"放在命名空间中,然后将结构名引用为NS::name。
namespace NS
{
template<typename T>
struct name {};
}
你可以使用你原来的x.template name()方法