C++ 触发静态_断言的部分模板专门化

C++ 触发静态_断言的部分模板专门化,c++,c++11,C++,C++11,考虑一下这个代码 template <typename T> struct delay : std::false_type{}; template <typename T> struct my_typelist { static_assert(delay<T>{}, ""); }; template <typename Tuple> struct test; template <typename T> struct tes

考虑一下这个代码

template <typename T>
struct delay : std::false_type{};

template <typename T>
struct my_typelist {
    static_assert(delay<T>{}, "");
};

template <typename Tuple>
struct test;

template <typename T>
struct test<my_typelist<T>> {
    void pass(){}
};

template <typename T>
void fail(const test<T> &){}

int main()
{
    test<my_typelist<int>> t;
    t.pass();
    fail(t);
}
模板
结构延迟:std::false_type{};
模板
结构我的类型列表{
静态断言(延迟{},“”);
};
模板
结构测试;
模板
结构测试{
无效传递(){}
};
模板
无效失败(常量测试&){}
int main()
{
试验t;
t、 通过();
失败(t);
}
不调用
fail()
代码编译并运行良好。但是,在任何函数中使用
t
似乎都会触发
my\u typelist
类中的
static\u assert
,即使该类从未实例化。尽管这个例子是人为设计的,但我在
std::tuple
中使用不完整的类型时遇到了同样的问题,尽管我只是简单地将
std::tuple
用作类型列表,并且从未实例化过它

为什么
static\u assert
只在我使用变量作为参数时触发,而不是在调用成员函数时触发?
my_typelist
是在什么上下文中实例化的,何时不是


请注意,我本应使用可变模板,但无论如何,都会出现错误,因此我选择使用最小公分母。

因此,让我们这样做:

首先从以下内容更改您的
static\u assert

它仍将继续


那么这里发生了什么

类模板即使在使用时也不会隐式实例化,除非在需要完全定义类型的上下文中使用

除非已明确指定类模板专用化 实例化([temp.explicit])或显式专门化 ([temp.expl.spec]),类模板专门化是隐式的 在以下上下文中引用专门化时实例化 需要完全定义的对象类型,或者 类类型影响程序的语义

请参阅,了解调用函数
fail(…)
实例化
myu类型列表的原因。基本上,在强制进行这种实例化的ADL中,您可以使用限定名
::foo
或括号来禁止

完整性:在其中一个(重点矿山):

:对于函数调用中的每个参数类型T,都有一组零个或多个关联的名称空间和一组零个或多个关联的类被视为

  • :如果T是类类型(包括联合),则其关联类为:类本身;其所属类别(如有); 以及它的直接和间接基类。它的相关名称空间 是其关联类的最内层封闭名称空间。此外,如果T是一个类模板专门化,则其关联的名称空间和类还包括:与为模板类型参数提供的模板参数类型关联的名称空间和类(不包括模板参数);任何模板参数都是其成员的名称空间;以及任何用作模板参数的成员模板都是成员的类。[ 注意:非类型模板参数不构成关联名称空间集。 — 尾注 ]

fail(t)
的情况下,如果
my_typelist
在其类定义中声明了名为
fail
的友元函数,则该函数将由找到(因为
my_typelist
test
的关联类)。在某些情况下,可以通过重载解析()选择该友元,而不是全局函数
fail
。因此,必须实例化并检查
my_typelist
的定义是否会发生这种情况。在
fail
周围添加括号将抑制依赖于参数的查找,并消除实例化
my_typelist
的需要,在这种情况下,
静态断言
不会触发()


t.pass()
的情况下,
my_typelist
不会被实例化,因为已知
t.pass()
将始终调用
test
的成员函数,而这不会受到
my_typelist
的完整性的影响。那么,为什么
t.pass()
不要求
my_typelist
是一个完全定义的类型,为什么
失败(t)
是否要求
my_typelist
成为完整类型?我看不出这是一种需要完全定义的对象类型或类类型的完整性影响语义的情况。将
fail
函数更改为
fail(…)
仍会触发错误,更改
static\u assert
以检查类型的完整性并使用前向声明的结构也会触发此错误。@cpplearner,如引用的文本所示。
t
类型的对象的大小始终是已知的,即
test
T
是。当然,
T
的类型肯定涉及名称
my_typelist
,只是当时作为一种类型而不是完全定义的类型,即使;至于为什么
my_typelist
在调用
fail
时被实例化,ADL开始检查相关的类,调用
::fail
(globaly限定)阻止它。编辑:正如您正确回答的那样。
template <typename T>
struct my_typelist {
    static_assert(delay<T>{}, "");
};
template <typename T>
struct my_typelist {
    static_assert(false, "");
};
template <typename T>
struct my_typelist {
    static_assert(delay<int>{}, "");
};