我喜欢在模板类中使用本地类来执行诸如“静态 if”之类的构造。但是我遇到了 gcc 4.8 不想编译我的代码的问题。但是 4.7 可以。
这个样本:
#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 类。
- 编写一个可以打印 A 和 B 的通用类 Test。
- 不要污染任何命名空间或类范围。
代码说明:
- 这只是一个干净的例子。
- 我使用这样的方法,因为我想概括构造“静态 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()。(见后文:'void Test::print()::IfB::print() [with T = A]')
如果我使用 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 错误吗?
- 还是 GCC 4.7 错误?也许代码不应该被编译。
- 或者这是我的错误,我不应该依赖编译器行为/不应该使用这种方法来实现“静态 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。希望这是 GCC 4.8 的错误并且可以修复。