【发布时间】:2016-04-12 15:41:36
【问题描述】:
几个 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.
我想这是对的 clang++,但我对 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 版本(如 3.8)和更新的 gcc(如 5.3)?可能有指导意义...
-
大部分最小化复制:coliru.stacked-crooked.com/a/713fbbbca7e8b8c5。我责怪缓存。
-
@T.C.哇,我完全忘记了“wtf 是 gcc 在做什么?”问题的一部分。很好的收获。
-
@Jesper Juhl - 不抱歉。是我当时可用的最新编译器吗?
标签: c++ c++11 g++ sfinae clang++