我喜欢在模板类中使用本地类来执行“static 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
任务:
代码说明:
所以问题。
此代码无法使用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();
^
其他信息:
这个简单的代码在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的bug,它可以修复。
答案 0 :(得分:3)
LocalClass
不是模板。 “未实例化但未使用”规则仅适用于类模板的成员函数。
也就是说,当实例化Test::print()
时,内部的所有内容都会生动,包括其本地类的未使用成员。
答案 1 :(得分:3)
您的代码中没有SFINAE。
SFINAE在模板参数推断和参数替换期间应用(SFINAE中的'S'代表替换)但是在您的程序中唯一替换是在A
替换模板参数列表中的T
时发生的。 Test
,这不会失败。
然后调用print()
实例化Test<A>::print()
,它不涉及任何替换,并且由于value.notExist();
无效而收到错误。
SFINAE必须在替换上下文中使用,例如函数调用引起的模板参数推导或使用默认参数推导模板参数时。