Using the detection idiom to determine whether a type has a constructor with a specific signature

南楼画角 提交于 2019-12-14 03:55:13

问题


I'm playing with the proposal of standard library support for the C++ detection idiom. It is a trait-like metafunction that determines whether a type T has a type member named T::type or a member function with a specific signature, e.g.:

#include <iostream>


template<class...>
using void_t = void;

template<class, template<class> class, class = void_t<>>
struct detect : std::false_type { };

template<class T, template<class> class Operation>
struct detect<T, Operation, void_t<Operation<T>>> : std::true_type { };


template<class T>
using bar_t = decltype(std::declval<T>().bar());

template<class T>
using bar_int_t = decltype(std::declval<T>().bar(0));

template<class T>
using bar_string_t = decltype(std::declval<T>().bar(""));


struct foo
{
    int bar() { return 0; }
    int bar(int) { return 0; }
};


int main()
{
    std::cout << detect<foo, bar_t>{} << std::endl;
    std::cout << detect<foo, bar_int_t>{} << std::endl;
    std::cout << detect<foo, bar_string_t>{} << std::endl;

    return 0;
}

The code above yields the expected output

1
1
0

You can play with a live demo. Now, I would like to test if a type T has a constructor with a specific signature, e.g. T::T(U) with another type U. Is it possible to do that using the detection idiom?


回答1:


Modify the detect class to allow for variadic args:

template <typename...>
using void_t = void;

template <typename AlwaysVoid, template <typename...> class Operation, typename... Args>
struct detect_impl : std::false_type { };

template <template <typename...> class Operation, typename... Args>
struct detect_impl<void_t<Operation<Args...>>, Operation, Args...> : std::true_type { };

Add an alias that hard-codes a void type:

template <template <typename...> class Operation, typename... Args>
using detect = detect_impl<void, Operation, Args...>;
//                         ~~~^

Write a detector:

template <typename T, typename... Us>
using has_constructor = decltype(T(std::declval<Us>()...));

Test your class:

static_assert(detect<has_constructor, foo, foo>{}, "!");

DEMO




回答2:


Even better: std::is_constructible


template<class U>
struct constructable_from {
  template<class T>
  using test_t = decltype(T(std::declval<U>()));
};

// usage
detect<foo, constructable_from<baz>::test_t> {}

This seems to be working with your code. One can easily extend this to support multi parameter constructors using variadic templates. I don't know whether this is "using the detection idiom", but it's what I've been using myself sometime ago.

My test code on ideone (it's a bit messy, I'm on mobile)



来源:https://stackoverflow.com/questions/35669304/using-the-detection-idiom-to-determine-whether-a-type-has-a-constructor-with-a-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!