类型扣除时间

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>是相同的类型,这让我想知道:

  1. 为什么标记的行// ???只对每种类型执行一次而不是一次?
  2. 有没有办法强制为每种类型执行一次行,最好不修改Holder的定义?

================================================== == 澄清:

(更接近)真实场景是:

  1. 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__.