如果构造函数是私有的,则 std::is_default_constructible<T> 会报错。

8
我有以下代码片段
#include <type_traits>
#include <boost/type_traits.hpp>

class C { C() { } };

int main()
{
   static_assert(!boost::has_trivial_default_constructor<C>::value, "Constructible");
   static_assert(!std::is_default_constructible<C>::value, "Constructible");
}

条件不相等,但第一个条件运行良好,而第二个构造函数会出现错误,因为它是私有的。编译器gcc 4.7...那么,这是gcc的bug,还是由标准定义的?

http://liveworkspace.org/code/NDQyMD$5

好的。既然这些条件确实不相等,我们可以使用类似以下的内容:

#include <type_traits>
#include <boost/type_traits.hpp>

class C { private: C() noexcept(false) { } };

int main()
{
   static_assert(!boost::has_nothrow_constructor<C>::value, "Constructible");
   static_assert(!std::is_nothrow_constructible<C>::value, "Constructible");
}

http://liveworkspace.org/code/NDQyMD 24美元

无论如何,我知道,静态断言不应该失败,因为类型确实不是默认可构造的,也不是无条件可构造的。问题是:为什么会有编译错误,而不是我的静态断言?


2
我现在明白你的意思了。看起来那就是一个 bug。 - Sergey Kalinichenko
请注意,这两个特征检查不同的属性。 - Xeo
@Xeo 好的... 那么 has_nothrow_constructoris_nothrow_constructible 呢? - ForEveR
1
使用即将发布的GCC 4.8的快照,两个代码片段均没有出现错误,并且结果与预期相符。 - Luc Danton
1个回答

5

看起来像是编译器的错误。让我们看下 SFINAE 的一个例子(类似的实现在 g++type_traits 头文件中使用)。

#include <type_traits>

class Private
{
    Private()
    {

    }
};

class Delete
{
    Delete() = delete;
};

struct is_default_constructible_impl
{
    template<typename T, typename = decltype(T())>
    static std::true_type test(int);

    template<typename>
    static std::false_type test(...);
};

template <class T>
struct is_default_constructible: decltype(is_default_constructible_impl::test<T>(0))
{

};

int main()
{
    static_assert(is_default_constructible<Private>::value, "Private is not constructible");
    static_assert(is_default_constructible<Delete>::value, "Delete is not constructible");
}

第二个断言按预期工作,我们不能推断出Delete类型,因为该类只有一个已删除的构造函数。但是当编译器尝试推断Private()的类型时,它会给出错误:Private::Private()是私有的。因此,我们有两个具有私有构造函数的类,但其中一个会出现错误,而另一个不会。我认为这种行为是错误的,但我无法在标准中找到确认。
附注:所有提供的代码都可以在clang上编译而没有任何错误。

我不明白... Private 简单来说就是 可以默认构造,对吧?是的,它有一个默认构造函数,但在 is_default_constructible_impl::test 的上下文中当然无法使用,因此断言失败,我认为这个特性的实现完全正确。- 但老实说,标准似乎没有在 §20.9.4.3 中明确提到构造函数是否应该是公共的;我只是认为这更有意义。 - Konrad Rudolph
@KonradRudolph,我解释错误了。编译器在尝试推断Private()的类型时会失败,而不是通过静态断言。或者我误解了你的意思? - awesoon
@KonradRudolph:断言没有失败。 std::is_constructible 本身失败了。标准确实要求构造函数是公共的(在§20.9.4.3/6中),但我认为它并不意味着类型特性应该导致编译错误。 - hpsMouse
谢谢。好的回答。现在我在MSVC 2012上测试了std::is_default_constructible...它可以工作,但是会断言并说该类型是可构造的(因此MSVC不会查看构造函数的可访问性)。 - ForEveR
1
@soon 啊,这样就不一样了。是的,现在我明白你的答案了,而且据我所见,你是正确的。 - Konrad Rudolph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接