有状态元编程中使用的模板 function/class 隐式实例化规则
Template function/class implicit instantiation rules used in stateful meta programming
我正在处理有关有状态元编程的代码示例。
原始代码示例可以从这个link中找到:http://b.atch.se/posts/non-constant-constant-expressions/#appendix-clang-workaround
为了理解这个技巧,我试着每次都稍微修改一下代码示例。以下是仍然有效的最新版本:
constexpr int adl_flag(int);
template <class Tag> struct writer {
friend constexpr int adl_flag(int) {
return 0;
}
};
template <int = adl_flag(0)> constexpr bool is_flag_usable(int) {
return true;
}
constexpr bool is_flag_usable (...) {
return false;
}
template <
class Tag = int,
bool B = is_flag_usable(0),
int = sizeof (writer<Tag>) // replace Tag with int
>
constexpr int f() {
return B;
}
int main() {
constexpr int a = f();
constexpr int b = f();
static_assert(a != b, "fail");
return 0;
}
对我来说,用 int 替换 Tag 似乎微不足道。但是这个替换实际上使 static_assert fail
.
我想这是因为编译器不再为第二次调用隐式实例化 f :
constexpr int b = f();
但是模板类型参数Tag似乎与此无关。请有人解释一下这里到底发生了什么。
我使用的编译器是g++ 5.4.1
。使用 -std=gnu++14
.
编译
sizeof(writer<int>)
是非依赖的。这意味着 wrapper<int>
在第一阶段查找中找到,当 f
被解析(一次)时。
另一方面,sizeof(writer<Tag>)
依赖于 Tag
。因此,它的查找被推迟到第二阶段,当 f
被实例化时(在它的每个调用站点)。
我正在处理有关有状态元编程的代码示例。 原始代码示例可以从这个link中找到:http://b.atch.se/posts/non-constant-constant-expressions/#appendix-clang-workaround
为了理解这个技巧,我试着每次都稍微修改一下代码示例。以下是仍然有效的最新版本:
constexpr int adl_flag(int);
template <class Tag> struct writer {
friend constexpr int adl_flag(int) {
return 0;
}
};
template <int = adl_flag(0)> constexpr bool is_flag_usable(int) {
return true;
}
constexpr bool is_flag_usable (...) {
return false;
}
template <
class Tag = int,
bool B = is_flag_usable(0),
int = sizeof (writer<Tag>) // replace Tag with int
>
constexpr int f() {
return B;
}
int main() {
constexpr int a = f();
constexpr int b = f();
static_assert(a != b, "fail");
return 0;
}
对我来说,用 int 替换 Tag 似乎微不足道。但是这个替换实际上使 static_assert fail
.
我想这是因为编译器不再为第二次调用隐式实例化 f :
constexpr int b = f();
但是模板类型参数Tag似乎与此无关。请有人解释一下这里到底发生了什么。
我使用的编译器是g++ 5.4.1
。使用 -std=gnu++14
.
sizeof(writer<int>)
是非依赖的。这意味着 wrapper<int>
在第一阶段查找中找到,当 f
被解析(一次)时。
sizeof(writer<Tag>)
依赖于 Tag
。因此,它的查找被推迟到第二阶段,当 f
被实例化时(在它的每个调用站点)。