检测类是否具有签名

时间:2017-04-24 10:24:34

标签: c++ template-meta-programming c++17

如果一个类有一个具有给定签名的构造函数,我如何编译时检测?具体来说,我想做以下几点:

class Archive
{
    // (...)

    template <typename T>
    T Read()
    {
        if constexpr(HasUnarchiveConstructor<T>())
        {
            return T(*this); // constructor accepts reference to Factory
        }
        else
        {
            T t;
            Unarchive(*this, t); // use stand alone function instead. (if this is not available either, compiling fails)
            return t;
        }
    }
}

有许多来源用于检测具有特定签名的功能。但是我无法将这些转换为构造函数。 source 1 source 2 source 3等等。

从我发现的源代码中我编译了以下内容以检测函数是否具有加号运算符:

template<typename T>
using HasUnarchiveConstructorImpl = decltype(std::declval<T>() + std::declval<T>());

template< typename T >
using HasUnarchiveConstructor = std::is_detected<HasUnarchiveConstructorImpl, T>;

如何将此扩展到我想要执行的检查?或者我怎么能以不同的方式做到这一点?

3 个答案:

答案 0 :(得分:10)

我会用:

if constexpr(std::is_constructible<T, Archive&>{})

此特征位于<type_traits>,并为您准备并调试。有一整套特征可以检测出这个问题的变体。

答案 1 :(得分:1)

  

如何将此扩展到我想要执行的检查?

您可以在decltype(...)表达式上使用T{...},如下所示:

struct Foo 
{ 
    Foo(Archive&) { }
};

struct Bar
{ 
    // unsupported
};

template<class T>
using HasUnarchiveConstructorImpl = 
    decltype(T{std::declval<Archive&>()});

template <class T>
using HasUnarchiveConstructor = 
    std::experimental::is_detected<HasUnarchiveConstructorImpl, T>;

static_assert(HasUnarchiveConstructor<Foo>::value);
static_assert(!HasUnarchiveConstructor<Bar>::value);

live example on wandbox

  

或者我怎么能以不同的方式做到这一点?

见Howard Hinnant的answer

答案 2 :(得分:0)

template <class T>
using HasUnarchiveConstructor = std::is_constructible<T, Archive&>;

wandbox