为什么这些复杂的代码可以用GCC 4.7编译,而不能用GCC 4.8
C++ GCC Why this sfinae code can be compiled with GCC 4.7, but not with 4.8?
我喜欢在模板类中使用局部类来执行像"静态if"这样的结构。但是我遇到了gcc 4.8不想编译我的代码的问题。
这个示例:
#include <type_traits>
#include <iostream>
#include <string>
using namespace std;
struct A {
void printA() {
cout << "I am A" << endl;
}
};
struct B {
void printB() {
cout << "I am B" << endl;
}
};
template <typename T>
struct Test {
void print() {
struct IfA {
constexpr IfA(T &value) : value(value) {
}
T &value;
void print() {
value.printA();
}
};
struct IfB {
constexpr IfB(T &value) : value(value) {
}
T &value;
void print() {
value.printB();
}
};
struct Else {
constexpr Else(...) {}
void print() {
}
};
typename conditional<is_same<T, A>::value, IfA, Else>::type(value).print();
typename conditional<is_same<T, B>::value, IfB, Else>::type(value).print();
}
T value;
};
int main() {
Test<A>().print();
Test<B>().print();
}
选项:
g++ --std=c++11 main.cc -o local-sfinae
任务:
- 给定A类和B类具有不同的打印接口。 写一个泛型类Test,可以打印a和b。不要污染任何命名空间或类的作用域。
代码描述:
- 我使用这样的方法,因为我想概括"静态if"的构造。看,我通过IfA和IfB类的字段传递参数,而不是直接传递给print()函数。
- 我经常使用这样的结构。
- 我发现这些建筑不应该在(污染)类范围内。我的意思是它们应该放在一个方法作用域中。
所以这个问题。
此代码不能用GCC 4.8编译。因为它检查所有类,即使它们从未使用过。但是它没有以二进制实例化它们(我已经注释了导致错误的行,并用gcc 4.8进行了编译)。证明:
$ nm local-sfinae |c++filt |grep "::If.*print"
0000000000400724 W Test<A>::print()::IfA::print()
00000000004007fe W Test<B>::print()::IfB::print()
看,没有Test::print()::IfB::print()。(见后:"空白试验::打印()::招标::打印()(T =]")
使用gcc 4.8编译上述代码的错误:
g++ --std=c++11 main.cc -o local-sfinae
main.cc: In instantiation of 'void Test<T>::print()::IfB::print() [with T = A]':
main.cc:36:9: required from 'void Test<T>::print() [with T = A]'
main.cc:49:21: required from here
main.cc:34:17: error: 'struct A' has no member named 'printB'
value.printB();
^
main.cc: In instantiation of 'void Test<T>::print()::IfA::print() [with T = B]':
main.cc:28:9: required from 'void Test<T>::print() [with T = B]'
main.cc:50:21: required from here
main.cc:26:17: error: 'struct B' has no member named 'printA'
value.printA();
^
- 是GCC 4.8的bug吗? 还是GCC 4.7的bug?也许代码不应该编译。
- 或者这是我的错误,我不应该依赖编译器的行为/不应该使用这种方法来实现"静态if"。
额外的信息:
这个简单的代码可以在4.7上编译,但不能在4.8上编译。我把它缩短了。
struct A {
void exist() {
}
};
template <typename T>
struct Test {
void print() {
struct LocalClass {
constexpr LocalClass(T &value) : value(value) {
}
T &value;
void print() {
value.notExist();
}
};
}
T value;
};
int main() {
Test<A>().print();
}
错误:
main.cc: In instantiation of 'void Test<T>::print()::LocalClass::print() [with T = A]':
main.cc:16:9: required from 'void Test<T>::print() [with T = A]'
main.cc:22:21: required from here
main.cc:14:17: error: 'struct A' has no member named 'notExist'
value.notExist();
^
测试了两个GCC 4.8版本:2012.10和2013.02。
LocalClass
不是模板。"未使用则未实例化"规则只适用于类模板的成员函数。
也就是说,当Test::print()
被实例化时,里面的所有东西都被激活,包括它的局部类中未使用的成员。
您的代码中没有SFINAE。
SFINAE应用于模板参数推导和参数替换(SFINAE中的'S'代表替换),但程序中的唯一替换发生在将Test
的模板参数列表中的A
替换为T
时,该替换不会失败。
然后调用实例化Test<A>::print()
的print()
,它不涉及任何替换,你会得到一个错误,因为value.notExist();
无效。
SFINAE必须在替换上下文中使用,例如由函数调用引起的模板实参推导或使用默认实参推导模板形参时。
相关文章:
- 为什么 gcc 编译这个而 msvc 没有
- 错误:使用 clang 没有可行的重载,使用 GCC 编译
- 带有自动参数的函数使用 GCC 编译,但不使用 Visual C++ 编译
- 使用 MINGW gcc 编译时,不会为 std::string 调用重载的新运算符
- Steam 回调在 Linux / GCC 编译期间触发警告
- 在其他容器中使用 boost::container::static_vector 时,GCC 编译错误"将'const s'绑定到类型's&'的引用丢弃限定符"
- 如何使用 GCC 编译指示启用选项 '-Werror'?
- 如何实现使用 gcc-4.4 编译的大向量初始化?
- 关于这个在 Linux 上使用 gcc 编译的程序中的 vtable,nm 告诉我什么?
- 使用 TDM GCC 5.1.0 编译 PDCurses36 时出错
- 为什么这段代码无法使用 gcc 4.8.5 编译,而使用 clang 编译正常
- 使用 std::addressof 时出现 GCC 7 编译错误
- 在类模板上使用 arm gcc 编译期间的隔离错误
- 使用 GCC 编译C++时如何包含 C11 标头?
- 类数据成员指针的非类型模板参数包无法使用 gcc 编译
- 是否可以使用 GCC 编译具有特定编译器标志的代码文件的一部分?
- 将 cctype 函数分配给 std::function,gcc 编译错误
- GCC 编译时出现警告:未知转义序列:"\040"
- 为什么以下代码不使用GCC编译,而是用Clang编译罚款
- GCC编译器,为较低版本的GCC编译应用程序