【发布时间】:2019-06-30 02:28:32
【问题描述】:
我今天早些时候遇到了这个问题。在以下代码中:
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;
}
编译和执行时:
g++ test.cpp -std=c++11 -o test
./test
它打印出来的是1而不是0,也就是说Helper<int>和Helper<bool>中的2个T是同一个类型,这让我很纳闷:
- 为什么标有
// ???的行只执行一次,而不是每种类型执行一次? - 有没有办法强制对每种类型的行执行一次,最好不修改 Holder 的定义?
================================================ ===== 说明:
(更接近)真实的场景是:
-
struct Holder是在第三方库的标头中定义的。 struct 的类型实际上很复杂,库编写器为用户提供了另一个宏:
template <bool, int> struct Holder {};
#define DEF_HOLDER(b) Holder<b, __COUNTER__>()
在程序的某个时刻,我想通过对类型进行别名来获取具有当前计数器的类型的“快照”,以便它可以在函数中使用:
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);
}
这里的问题是下面2个用法的语义不一致,如图所示:
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;
}
在我的用例中,多次调用 Func 返回不同的类型很重要,就像直接调用 DEF_HOLDER 一样。
【问题讨论】:
-
即使它打印 1 并不意味着
Helper<int>和Helper<bool>是同一类型。它们是不同的类型static_assert(false == ::std::is_same_v<Helper<int>, Helper<bool>>);。目前尚不清楚您要在这里实现什么目标。 -
@VTT - OP 询问
Helper<bool>::T和Helper<int>::T- 这里是同一类型。 -
@StoryTeller 是的,但是如果 OP 想要从
Helper<bool>和Helper<int>中获得两种不同的类型,他可以自己使用这些类型。或者制作类似struct T{};的东西,而不是using T = Holder<__COUNTER__>;。所以不清楚他为什么需要Holder类型。 -
@VTT - 我想这是元编程尝试的某种简化形式。我同意这可能是一个 XY 问题。
-
@kkspeed - 与其专注于问题 2,您认为这是解决您实际问题的方法,您介意告诉我们关于您的最终目标的一两件事吗?就像我已经说过的,这有一种XY question 的感觉。
标签: c++ templates c-preprocessor