为什么未使用的成员模板功能的类模板实例化失败

问题描述 投票:4回答:2

这有什么问题:

#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(trunk):失败
  • x86-64 clang 6.0.0:编译
  • x86-64 clang 7.0.0及更高版本:失败
  • x64 msvc v19.22:编译
  • x64 msvc v19.23(内部测试):失败

那么为什么最近有更多的编译器拒绝呢?实例化B<A>时,不清楚将以哪种形式使用f1或是否完全使用。那么为什么编译器会抱怨呢? f1成员模板功能是否仅在确实使用时才检查?


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

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

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

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

c++ templates
2个回答
3
投票

原因是std::is_constructible需要完整的类型:(Table 42

模板

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

前提条件

T应该是完整类型,cv无效,或者是未知范围的数组。

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


2
投票

cppreference上的is_copy_constructible<T>

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

因此,您似乎在较早的编译器版本中只有普通的UB,而较新的版本则足以告诉您A必须是完整类型。

[请注意,在使用UB的情况下,编译器不会发出错误,但是可以这样做,这是一件好事。

© www.soinside.com 2019 - 2024. All rights reserved.