【问题标题】:Why does is_constructible claim something is constructible when it isn't?为什么 is_constructible 声称某些东西不是可构造的?
【发布时间】:2013-01-26 18:46:38
【问题描述】:

以下程序在使用 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);
}

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

【问题讨论】:

  • 您应该使用 enable_if 从可能的 foo 中删除整数。

标签: c++ templates c++11 constructor typetraits


【解决方案1】:

这是标准必须说的(§20.9.5/6),我强调:

给定以下函数原型:

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

模板特化的谓词条件 当且仅当满足is_constructible&lt;T, Args...&gt; 对于某些发明,以下变量定义将是格式良好的 变量t:

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

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

访问检查是在与T 无关的上下文中执行的,并且 任何Args只有直接上下文的有效性 考虑变量初始化。 [ 注意: 初始化可能会导致副作用,例如 类模板特化和函数模板特化, 隐式定义函数的生成,等等。这样的一面 影响不在“直接上下文”中,并且可能导致 程序格式错误。 ——尾注 ]

只有在模板构造函数被实例化时,断言才会失败。但是,正如注释中所澄清的那样,该断言不在所考虑的变量定义的直接上下文中,因此不会影响其“有效性”。因此编译器可以将该定义视为有效,从而声称foo 确实可以从int 构造,即使实际上尝试从int 构造foo 会导致程序格式错误。

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

【讨论】:

  • 请注意,这只是有意义的。 std::is_constructible&lt;&gt; 确定是否有构造函数接受参数,而不是构造函数定义良好。考虑在处理is_constructible 时,编译器不需要看到构造函数的定义(以及static_assert)。如果你想启动它,使用 SFINAE 禁用 int 的构造函数,或者添加 foo(int)=delete; 这会将构造函数标记为不可用(不是 100% 肯定最后一种方法,但它应该可以工作)跨度>
  • 您能否解释一下您的声明,即实现是 1) 允许 is_constructible 产生 false 和 2) 允许拒绝原始程序?
【解决方案2】:

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>();
}

【讨论】:

    猜你喜欢
    • 2012-12-10
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2016-05-01
    • 2012-02-26
    • 2020-02-07
    • 2012-01-22
    • 2017-02-16
    相关资源
    最近更新 更多