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:
// ???
is executed only once instead of once for each of the type?==================================================== Clarifications:
The (closer to) real scenario is:
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__
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With