Type deduction time

  • A+
Category:Languages

I ran into this problem earlier today. In the following code:

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; } 

When compiled and executed with:

g++ test.cpp -std=c++11 -o test ./test 

It prints out 1 instead of 0, meaning that the 2 Ts in Helper<int> and Helper<bool> are the same type, which makes me wonder:

  1. Why the line marked with // ??? is executed only once instead of once for each of the type?
  2. Is there a way to force the line to be executed once for each of the type and preferably without modifying the definition of Holder?

==================================================== Clarifications:

The (closer to) real scenario is:

  1. The struct Holder is defined in a header from a third-party library. The type for the struct is actually very complicated and the library writer provides users with another macro:
template <bool, int> struct Holder {};  #define DEF_HOLDER(b)  Holder<b, __COUNTER__>() 

At some point of the program, I want to take a "snapshot" of the type with current counter by aliasing the type so that it could be used in a function:

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); } 

The problem here is that the following 2 usage has inconsistent semantics as illustrated:

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; } 

In my use case, it is important for multiple invocation of Func to return different types as it does with invoking DEF_HOLDER directly.

 


The symbol __COUNTER__ is a preprocessor macro, it's expanded once only.

That means T will always be Holder<0> (since __COUNTER__ starts at zero), no matter the type used for the template Helper.

See e.g. this GCC predefined macro reference for more information about __COUNTER__.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: