部分模板专用化触发static_assels
Partial template specialization triggering static_asserts
考虑这个代码
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);
}
在不调用fail()
的情况下,代码编译并运行良好。然而,在任何函数中使用t
似乎都会触发my_typelist
类中的static_assert
,即使该类从未实例化。尽管这个例子是人为设计的,但我在std::tuple
中使用不完整的类型时遇到了同样的问题,尽管我只是将std::tuple
用作类型列表,并且从未实例化过它
为什么static_assert
只在我将变量用作参数时触发,而不是在我调用成员函数时触发?my_typelist
是在什么情况下实例化的,什么时候不实例化?
请注意,我本来会使用可变模板,但不管怎样,错误都会发生,所以我选择使用最低公分母。
在fail(t)
的情况下,如果my_typelist<int>
在其类定义中声明了一个名为fail
的友元函数,则该函数将通过参数相关查找找到(因为my_typelist<int>
是test<my_typelist<int>>
的关联类)。在某些情况下,可以通过过载分辨率(demo)来选择该朋友,而不是全局函数fail
。因此,必须实例化并检查my_typelist<int>
的定义,看看是否会发生这种情况。在fail
周围添加括号将抑制与参数相关的查找,并消除实例化my_typelist<int>
的需要,在这种情况下,static_assert
不会被触发(演示)。
在t.pass()
的情况下,my_typelist<int>
不被实例化,因为已知t.pass()
将始终调用test<my_typelist<int>>
的成员函数,并且这不会受到my_typelist<int>
的完整性的影响。
所以,让我们走这条路:
首先从以下工作代码更改您的static_assert
:
template <typename T>
struct my_typelist {
static_assert(delay<T>{}, "");
};
到此:
template <typename T>
struct my_typelist {
static_assert(false, "");
};
它马上就要着火了。请注意,false
表达式不依赖于任何类型。
现在,将其更改为不依赖于任何模板参数的delay<T>
类型,例如char
、int
等:
template <typename T>
struct my_typelist {
static_assert(delay<int>{}, "");
};
它仍然会立即起火。
这里发生了什么?
类模板即使在使用时也不会隐式实例化,除非它在需要完全定义类型的上下文中使用。
temp.inst/1
除非类模板专门化已明确实例化的(〔temp.explicit〕)或显式专用的([temp.exp.spec]),类模板专门化是隐式的在上下文中引用专门化时实例化需要一个完全定义的对象类型,或者当类类型会影响程序的语义。
请参阅@cpplearner的答案,了解为什么调用函数fail(...)
会实例化my_typelist<int>
。基本上,ADL会强制执行这样的实例化,您可以使用限定名称::foo
或括号来抑制。
完整性:在ADL的一个规则中(强调矿):
basic.lookup.argdep/2:对于函数调用中的每个参数类型T,都有一组零个或多个关联的命名空间和一组零或多个要考虑的关联类。
。。。。
basic.lookup.argdep/2.2:如果T是一个类类型(包括并集),则其关联的类为:类本身;其所属类别(如有);及其直接和间接基类。其关联的命名空间是其关联类的最里面的封闭命名空间。此外,如果T是类-模板专用化,其关联的命名空间和类还包括:与为模板类型参数(不包括模板模板参数)提供的模板参数的类型相关联的命名空间和类别;任何模板模板参数都是其成员的命名空间;以及用作模板模板参数的任何成员模板都是其成员的类[注意:非类型模板参数对关联的命名空间集没有贡献。—尾注]
。。。。
- 为什么即使使用-cudart-static进行编译,库用户仍然需要链接到cuda运行时
- 如何处理 c++ 中类实现中的"invalid use of non-static data member"?
- 收到错误"invalid use of non-static data member 'stu::n' "
- LNK1104:无法打开libpjproject-i386-Win32-vc14-Debug-Static.lib
- 我应该在 C++ 中何时/为什么使用 STATIC?
- 在VS2019项目中集成ImageMagick:x64-windows-static library
- 如何处理Boost Spirit X3导致Visual Studio 2019 "static initialization order fiasco"?
- "static char __ = []() -> char"的含义
- 当初始值设定项是基类名时'initializer does not name a non-static data member or base class'错误
- 无法在 DLL 中链接 SDL2-static.lib
- 如何摆脱C++中未解析的外部符号"private: static char"错误?
- C++线程"Call to non-static member function without an object argument"
- 出现这种错误的原因是什么"invalid use of non-static data member "
- static是如何使用ClassA::m_variable处理所有类对象的
- LNK2001:未解析的外部符号public:static类std::vector
- 使用-static libstdc++时std::线程弱,因此在运行时会导致崩溃
- 你能初始化unique_ptrs "static const vectors"吗?(C++17 与 GCC 7.3)
- 为什么异常不适用于 OSX 上的 gcc7 和 -static-libgcc?
- 数组在 C++ 中不使用 static in 函数时不会修改
- 错误 LNK2001:未解析的外部符号"private: static class Game Game::game_"