boost :: proto :: is_aggregate在聚合类型时返回false

时间:2015-11-11 09:54:09

标签: c++ boost boost-proto

在测试聚合类型时,我尝试使用boost :: proto :: is_aggregate来检查我创建的类型是否真正聚合。我写了这段代码:

#include <iostream>
#include <boost\proto\traits.hpp>

struct IsAggregate
{
    IsAggregate &operator=(IsAggregate const &rhs) {}
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << boost::proto::is_aggregate<IsAggregate>() << std::endl;

    return 0;
}

我希望输出为真,因为聚合类型可以定义一个拷贝赋值运算符(根据这个:What are Aggregates and PODs and how/why are they special?

但输出结果是假的。

我还使用了前一个答案中的聚合类,它应该返回true但是返回false。

使用英特尔编译器和MSVC在Boost 1.5.9上进行了测试。

有关为何发生这种情况的任何想法?

1 个答案:

答案 0 :(得分:6)

Proto的特性显然不适合更广泛的使用。

默认只调用POD聚合,然后只显示3 - 库内部类型作为聚合。文档中描述的行为表明存在划痕痒(make<>函数需要一种方法来了解哪些类型与T{}一起使用,哪些类型与T()一起使用。

退一步,你应该首先重新考虑你想要这个特性的原因。您最有可能使您的概念检查更具体。

向标准库添加特征的提议已得到广泛支持的拒绝:

        
    

我对这个特性有所保留。我们在添加无用的特征如is_pod和is_literal_type时犯了一个错误,我们不应该通过添加更多无用的特征来弥补这个错误。

         

在我看来,类型traits应该捕获类型的可观察属性(例如,“我可以从braced-init-list直接初始化这个类型吗?”),而不是核心语言ephemera(例如“这种类型”遵守文字类型规则,这是一个需要编译器诊断的拐杖?“或”将支持此类型的初始化执行聚合初始化,还是会调用构造函数?“)。

         

另外,我认为类型应该能够在聚合之间切换并提供等效的构造函数集,而不必担心有人可能会观察到差异。

  

我已经查看了要求,并得出结论很难/不可能做出一个万无一失的实施。我无法以编程方式解决的第一个要求是

  

没有基类(第10条)

没有办法告诉某个班级没有(公共,空等)基类。

所以我能提出的最好的事情只是近似:

template <typename T>
struct is_aggregate : std::integral_constant<bool,
        std::is_pod<T>() or
        (
                std::is_trivially_constructible<T>() 
            and std::is_trivially_destructible<T>()
            and std::is_standard_layout<T>()
            and not std::is_polymorphic<T>()
        )
    >
{ };

考虑到这些限制,它似乎相当不错,至少/比Proto的内部特质好很多/更好。

CAVEAT 这并未解决c ++ 11 / c ++ 14中的细微变化(例如与类内成员初始值设定项相关)。还有一些用于构成上述近似的特征在各种编译器版本(特别是MSVC,我记得)上存在已知问题,所以不要相信这个特性在所有语言/库版本中都是准确的。

<强> Live On Coliru

#include <iostream>
#include <type_traits>
#include <string>

template <typename T>
struct is_aggregate : std::integral_constant<bool,
        std::is_pod<T>() or
        (
                std::is_trivially_constructible<T>() 
            and std::is_trivially_destructible<T>()
            and std::is_standard_layout<T>()
            and not std::is_polymorphic<T>()
        )
    >
{ };

namespace simple { // ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }
    };

    static_assert(is_aggregate<X>(), "");

    void foo() { X x { 42 }; (void) x; }
}

namespace usr_defined_ctor { // NOT ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }

        X() {}
    };

    static_assert(!is_aggregate<X>(), "");

    //void foo() { X x { 42 }; (void) x; }
}

namespace defaulted_ctor { // ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }

        X() = default;
    };

    static_assert( is_aggregate<X>(), "");

    void foo() { X x { 42 }; (void) x; }
}

namespace static_data_members { // ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }

        X() = default;

        static const bool yeah = true;
    private:
        static const bool no = true;
    protected:
        static const std::string problem;
    };

    bool const X::yeah;
    bool const X::no;
    std::string const X::problem = "whatsoever";

    static_assert( is_aggregate<X>(), "");

    void foo() { X x { 42 }; (void) x; }
}

namespace private_non_static_data_members { // NOT ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { (void) oops; return *this; }

    private:
        bool oops;
    };

    static_assert(!is_aggregate<X>(), "");

    //void foo() { X x { 42, true }; (void) x; }
}

namespace protected_non_static_data_members { // NOT ok
    struct X {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }

    protected:
        bool oops;
    };

    static_assert(!is_aggregate<X>(), "");

    //void foo() { X x { 42, true }; (void) x; };
}

namespace have_base_class { // NOT ok
    struct B {};
    struct X : B {
        int x;
        X &operator=(X const &/*rhs*/) { return *this; }
    };

    static_assert(is_aggregate<X>(), ""); // FALSE POSITIVE: the below fails to compile

    //void foo() { X x { 42 }; (void) x; };
}

int main() { }

Coliru干净地编译(没有静态断言):

g++ -std=c++0x -O2 -Wall -pedantic -pthread main.cpp
g++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
g++ -std=c++1y -O2 -Wall -pedantic -pthread main.cpp
g++ -std=c++1z -O2 -Wall -pedantic -pthread main.cpp
clang++ -std=c++0x -O2 -Wall -pedantic -pthread main.cpp
clang++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
clang++ -std=c++1y -O2 -Wall -pedantic -pthread main.cpp
clang++ -std=c++1z -O2 -Wall -pedantic -pthread main.cpp
clang++ -stdlib=libc++ -std=c++0x -O2 -Wall -pedantic -pthread main.cpp
clang++ -stdlib=libc++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
clang++ -stdlib=libc++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
clang++ -stdlib=libc++ -std=c++1y -O2 -Wall -pedantic -pthread main.cpp
clang++ -stdlib=libc++ -std=c++1z -O2 -Wall -pedantic -pthread main.cpp