为什么is_constructible声称某物是可构造的,而实际上并非如此?

Why does is_constructible claim something is constructible when it isn't?

本文关键字:并非如此 实际上 constructible is 为什么      更新时间:2023-10-16

以下程序在使用GCC 4.7和clang 3.2编译时,产生"1"作为输出。

#include <type_traits>
struct foo {
    template<typename T>
    foo(T) {
        static_assert(not std::is_same<int, T>(), "no ints please");
    }
};
#include <iostream>    
int main() {
    std::cout << std::is_constructible<foo, int>();
}

这是令人困惑的。 foo显然无法从int中构建!如果我将main更改为以下内容,则由于静态断言失败,两个编译器都拒绝它:

int main() {
    foo(0);
}

为什么两个编译器都说它是可构造的?

这就是标准(§20.9.5/6(的内容,我强调:

给定以下函数原型:

template <class T>
typename add_rvalue_reference<T>::type create();

模板专用化的谓词条件 is_constructible<T, Args...>当且仅当 以下变量定义对于某些发明的格式很好 可变t

T t(create<Args>()...);

[ 注意:这些标记永远不会被解释为函数 声明。—尾注 ]

访问检查的执行就像在与T和 任何Args.只有直接上下文的有效性 考虑变量初始化。[注评价 初始化可能会导致副作用,例如实例化 类模板专用化和函数模板专用化, 生成隐式定义的函数,等等。这样的一面 效果不在"直接上下文"中,可能导致 程序格式不正确。—尾注 ]

仅当实例化模板构造函数时,断言才会失败。然而,正如说明中所澄清的,这种断言不在所考虑的变量定义的直接上下文中,因此不影响其"有效性"。因此编译器可以将该定义视为有效,从而声称foo确实可以从int构造,即使实际上试图从int构造一个foo会导致程序格式错误。

请注意,编译器也允许编译器根据断言拒绝原始程序,而不是is_constructible产生假,即使两者都没有。

foo2是你的foofoo1是一个 foo 可以做您希望您的foo做的事情。

#include <type_traits>
#include <utility>
struct foo1 {
  template<typename T,typename=typename std::enable_if< !std::is_same<int, T>::value >::type>
  foo1(T) {
    static_assert(not std::is_same<int, T>(), "no ints please");
  }
};
struct foo2 {
  template<typename T>
  foo2(T) {
    static_assert(not std::is_same<int, T>(), "no ints please");
  }
};
#include <iostream>    
int main() {
  std::cout << std::is_constructible<foo1, int>();
  std::cout << std::is_constructible<foo2, int>();
}