kks*_*eed 8 c++ templates c-preprocessor
我今天早些时候遇到了这个问题.在以下代码中:
template <int> struct Holder {};
template <typename> struct Helper { using T = Holder<__COUNTER__>; }; // ???
int main() {
auto a = typename Helper<bool>::T();
auto b = typename Helper<int>::T();
std::cout << (typeid(a) == typeid(b)) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译和执行时:
g++ test.cpp -std=c++11 -o test
./test
Run Code Online (Sandbox Code Playgroud)
它打印出1而不是0,这意味着2 Ts Helper<int>和Helper<bool>是相同的类型,这让我想知道:
// ???只对每种类型执行一次而不是一次?================================================== == 澄清:
(更接近)真实场景是:
struct Holder在第三方库的标头中定义.结构的类型实际上非常复杂,库编写器为用户提供了另一个宏:template <bool, int> struct Holder {};
#define DEF_HOLDER(b) Holder<b, __COUNTER__>()
Run Code Online (Sandbox Code Playgroud)
在程序的某个时刻,我想通过对类型进行别名来获取具有当前计数器的类型的"快照",以便可以在函数中使用它:
template <bool b>
struct Helper { using T = decltype(DEF_HOLDER(b)); };
template <bool b, typename R = typename Helper<b>::T>
R Func() {
return R();
}
// Note that the following does not work:
// Since the 2 types generated by DEF_HOLDER do not match.
template <bool b>
auto Func() -> decltype(DEF_HOLDER(b)) {
return DEF_HOLDER(b);
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是以下两种用法具有不一致的语义,如图所示:
int main() {
auto a = DEF_HOLDER(true);
auto b = DEF_HOLDER(true);
auto c = Func<true>();
auto d = Func<true>();
std::cout << (typeid(a) == typeid(b)) << std::endl; // prints 0
std::cout << (typeid(c) == typeid(d)) << std::endl; // prints 1
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在我的用例中,重要的是多次调用Func返回不同类型,就像DEF_HOLDER直接调用一样.
Som*_*ude 13
符号__COUNTER__是预处理器宏,它只扩展一次.
这意味着T将永远是Holder<0>(因为__COUNTER__在零点开始),不管使用的模板类型Helper.
有关详细信息,请参阅此GCC预定义宏参考__COUNTER__.