![](/img/trans.png)
[英]g++ and clang++ different behaviour with variable template and SFINAE
[英]g++ and clang++ different behaviour with SFINAE and SFINAE failure
关于C ++ 11专家的几个问题。
我正在与SFINAE战斗,我遇到了一个奇怪的案例,其中g ++(4.9.2)和clang ++(3.5.0)表现不同。
我准备了以下示例代码。 对不起,但我无法更明确地做到这一点。
#include <string>
#include <iostream>
#include <typeinfo>
#include <type_traits>
template <typename X>
class foo
{
private:
template <typename R>
using enableIfIsInt
= typename std::enable_if<std::is_same<X, int>::value, R>::type;
public:
foo ()
{ }
template <typename R = void>
enableIfIsInt<R> bar ()
{ std::cout << "bar: is int\n"; }
void bar ()
{
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
<< typeid(enableIfIsInt<void>).name() << "}\n";
}
};
int main ()
{
foo<long> fl;
foo<int> fi;
fl.bar();
fi.bar();
return 0;
}
我的想法是创建一个模板foo<X>
类,通过SFINAE可以根据X
模板参数以一种方式或另一种方式定义方法。
该程序与g ++ 4.9.2编译良好,但clang ++ 3.5.0给出以下错误
test.cpp:13:36: error: no type named 'type' in
'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable
this declaration
= typename std::enable_if<std::is_same<X, int>::value, R>::type;
^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:26:23: note: in instantiation of template type
alias 'enableIfIsInt' requested here
<< typeid(enableIfIsInt<void>).name() << "}\n";
^
test.cpp:36:7: note: in instantiation of member function
'foo<long>::bar' requested here
fl.bar();
^
1 error generated.
我想这是正确的铿锵++,但我对C ++ 11专家的第一个问题是:谁对吗? g ++或clang ++?
关于g ++生成的程序输出,如下所示
bar: isn't int; is [i]{v}
所以g ++似乎忽略了fl.bar();
指令。
现在稍微改变一下:我用这种方式修改了foo<X>::bar()
的第二个版本
void bar ()
{ std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n"; }
删除函数憎恶中的std::enable_if
。 现在g ++和clang ++都在编译时没有问题,并且对于程序的两个编译版本的输出都是
bar: isn't int; is [l]
bar: isn't int; is [i]
所以,我的第二个问题是:我做错了什么? 为什么,在int
情况下,我没有获得foo<X>::bar()
的"is int"
版本?
如果我做得有些愚蠢,请耐心等待我:我正在努力学习C ++ 11。
抱歉我的英语不好。
clang的错误不是来自替换失败。 它来自这里:
void bar ()
{
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
<< typeid(enableIfIsInt<void>).name() << "}\n"; // <==
}
enableIfIsInt<void>
不在直接上下文中,这是X
的硬故障不是int
。 你根本无法在该上下文中使用该表达式。
删除后 - 始终调用非模板bar()
。 这是因为两个函数都是等效匹配,非模板比重载解析中的模板更受欢迎。
所以真正的解决方案是使用tag-dispatching:
void bar() { bar(std::is_same<X, int>{}); }
void bar(std::true_type ) {
std::cout << "bar: is int\n";
}
void bar(std::false_type ) {
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n";
}
两个编译器愉快地产生:
bar: isn't int; is [l]
bar: is int
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.