当前位置: 首页 > 知识库问答 >
问题:

未使用成员模板函数的类模板实例化失败的原因

公西苗宣
2023-03-14

这有什么问题:

#include <type_traits>

struct A;

template<typename T>
struct B
{
    template<typename=std::enable_if<std::is_copy_constructible<T>::value>>
    void f1() {}
};

template<typename T>
struct C {};


// Type your code here, or load an example.
int main() {
    // Following fails
    B<A> b;
    // Could use this:
    // b.f1<C>();

    // This complies
    C<A> c;

    return 0;
}

/* This to be in or not doesn't make a difference
struct A
{};
*/

我在这里尝试过:用不同的编译器https://godbolt.org/z/NkL44s:

  • x86-64 gcc 9.2:编译
  • x86-64 gcc(主干):失败
  • x86-64 clang 6.0.0:编译
  • x86-64 clang 7.0.0及更高版本:失败
  • x64 msvc v19.22:编译
  • x64 msvc v19.23(内部测试):失败

那么,为什么最近的编译器会拒绝这一点呢?实例化<code>B时

编辑:
如评论中所述,我在上面的代码中犯了一个无意的错误:std::enable_if应该是std::enable_if_t,就像在这个更正的游乐场中一样:https://godbolt.org/z/cyuB3d

这将改变编译器无错误传递此代码的画面:

  • gcc:失败
  • clang:失败
  • x64 msvc v19.22:编译
  • x64 msvc v19.23(内部测试):失败

但是,问题仍然存在:为什么从未使用过的函数的默认模板参数会导致编译失败?

共有2个答案

齐航
2023-03-14

is_copy_constructable上的cppreference

T应该是一个完整的类型,(可能是cv限定的)void,或者是一个未知界限的数组。否则,行为未定义。

所以看起来在旧的编译器版本中你只有普通的UB,而新的版本很好的告诉你< code>A必须是一个完整的类型。

请注意,在存在 UB 的情况下,编译器不需要发出错误,但他们可能会这样做,这是一件好事。

廉雅惠
2023-03-14

原因是std::is_constructible需要一个完整的类型:(表42)

template <class T>
struct is_­copy_­constructible;

T应为完整类型、cv void或未知界限数组。

未能满足库“应”的要求会导致未定义的行为。

 类似资料:
  • 我有一个模板化的C++类,它也有一个模板化的成员函数。这个成员函数的模板参数以特定的方式依赖于类的模板参数(请参阅下面的代码)。我正在为其模板参数的两个不同值实例化(而不是专门化)该类。一切都在这一点上进行。但是,如果我调用模板化的成员函数,对第一个实例化对象的调用只会编译,而不会编译第二个。似乎编译器没有为模板类的第二次实例化实例化模板化成员函数。我正在使用“g++filename.cpp”编译

  • 是否有人知道此显式特化是否有效: clang 主干 (12/3/2013) 给出以下错误: f:...\test.cpp:36:20: 错误: 从类 'O' 中出线定义 “Fun” 没有定义 1生成错误。 任何来自标准的支持参考来证明你的答案将不胜感激! 注意:我有点惊讶这是一个错误——我认为应该为任何以< code >开始实例化“Fun”的模板参数族选择专门化 这是一个叮当的错误还是我期望中的错

  • [dcl.spec.auto]/14国[强调我的]: 显式实例化声明不会导致使用占位符类型声明的实体的实例化,但也不会阻止根据需要对该实体进行实例化以确定其类型。[示例: -结束示例] 和[temp.explicat]/11声明[强调我的]: 现在,考虑我们是否在类模板中的friend声明中定义了friend函数: 如果在同一翻译单元中实例化了的多个专门化,则将违反[basic.def.odr]/

  • 我有一个问题,我想在下面的代码中专门化模板类的模板成员函数。这个问题的答案是模板类成员函数的显式特化,这似乎表明它无法完成。这是正确的吗,如果是这样,我可以使用任何解决方法,以便在编译时通过内联inc函数进行扩展? 非常感谢! g吐槽道: test2.cpp:32:13: 错误: 非命名空间作用域中的显式专用化 'struct IdxIterator' test2.cpp:32:25: 错误: 非

  • 我试图用成员模板函数实现一个可变类模板,其模板参数独立于类模板参数,但在定义成员模板时遇到了问题。 我将问题简化为尝试编译此文件(抱歉,无法进一步简化): 在尝试编译(C 11)时,我遇到以下错误: 我很确定它归结为第一个和第五个错误,但不知道我做错了什么。为什么

  • 本文向大家介绍C++函数模板与类模板实例解析,包括了C++函数模板与类模板实例解析的使用技巧和注意事项,需要的朋友参考一下 本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解。具体内容如下: 泛型编程(Generic Programming)是一种编程范式,通过将类型参数化来实现在同一份代码上操作多种数据类型,泛型是一般化并可重复使用的意思。泛