【发布时间】:2021-12-29 12:53:42
【问题描述】:
我一直在试验一个可组合管道的系统,它涉及一组“阶段”,可以模板化。每个阶段都处理自己的设置、执行和清理,模板推导用于构建管道使用的最小“状态”列表。这需要相当多的样板模板代码,这些代码已经显示出一些明显不协调的行为。尽管实验成功了,但实际上将其滚动到我们的代码库中会由于无效的实例化而导致错误。
花了一些时间来找出玩具(工作)解决方案与更丰富的版本之间的区别,但最终将其缩小到明确的命名空间规范。
template<typename KeyType = bool>
struct bind_stage
{
static_assert(!std::is_same<KeyType, bool>::value, "Nope, someone default instantiated me");
};
template<typename BoundStage, typename DefaultStage>
struct test_binding {};
template<template<typename...>class StageTemplate, typename S, typename T>
struct test_binding <StageTemplate<S>, StageTemplate<T>> {};
template<typename T>
auto empty_function(T b) {}
然后我们的主要:
int main()
{
auto binder = test_binding<bind_stage<int>, bind_stage<>>();
//empty_function(binder); // Fails to compile
::empty_function(binder); // Compiles happily
return 0;
}
现在,我不确定我是否预计会失败。一方面,我们创建了一个test_binder<bind_stage<int>,bind_stage<bool>>,它显然将无效的实例化bind_stage<bool> 作为其类型定义的一部分。哪个应该无法编译。
另一方面,它纯粹是作为一个名称,而不是一个定义。在这种情况下,它可能只是一个前向声明的模板,我们希望它能够工作,只要外部模板中没有任何东西真正具体引用它。
我没想到的是两种不同的行为,这取决于我是否添加了(理论上是多余的)全局命名空间说明符。
我已经在 Visual Studio、Clang 和 GCC 中尝试过这段代码。所有人都有相同的行为,这使我远离编译器错误。这种行为是由 C++ 标准中的某些内容解释的吗?
编辑: Daniel Langr 的另一个例子对我来说意义不大:
template <typename T>
struct X {
static_assert(sizeof(T) == 1, "Why doesn't this happen in both cases?");
};
template <typename T>
struct Y { };
template <typename T>
void f(T) { }
int main() {
auto y = Y<X<int>>{};
// f(y); // triggers static assertion
::f(y); // does not
}
X<int> 在定义 Y<X<int>> 时被实例化,或者不是。在非指定范围内使用函数有什么关系?
【问题讨论】:
-
test_binding
, bind_stage >();顺便说一句。不知道为什么 2. 语句会编译。应该完全一样,你甚至没有使用命名空间等。 -
确实如此,但部分意图是尝试查看是否可以使用特定实例化和默认实例化之间的差异来指定一组“绑定”类型,这些类型将在所有阶段持续存在在使用相同“密钥”的管道中。
-
您可以考虑创建一个问题的最小示例。它现在太复杂了,有很多分散注意力的代码(例如,可变参数模板、模板模板参数等)。考虑以下一个:wandbox.org/permlink/GS8xSEQMQOOoaSt6。它更简单,据我所知,它表现出同样的问题。 (如果您愿意,可以将代码粘贴到更新的问题中。)
-
这显然归结为非限定名与限定名查找。对于非限定名称查找,似乎
Y本身不需要是完整类型,因此X<int>不需要是完整类型,因此它不是implicitly instantiated。但是对于限定名称查找,显然 Y 和X<int>必须被隐式实例化(为什么?)。我似乎找不到会这样说的标准部分。Y<X<int>>似乎不需要隐式实例化X<int>(因为后者的完整性无关紧要)。 -
对于它的价值,EDG(如 Visual Studio Intellisense)与所有其他编译器一致:i.stack.imgur.com/DfP7E.png
标签: c++ templates language-lawyer instantiation template-argument-deduction