Using a discovery identifier to determine if a type has a constructor with a specific signature

I play with offering standard library support for the C ++ detection idiom . This is a metacharacter similar to an attribute that determines whether type T has a type member named T::type or a function member with a specific signature, for example:

 #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 above code gives the expected output

 1 1 0 

You can play with live demo . Now I would like to check if type T constructor with a specific signature, for example. T::T(U) with a different type of U Can this be done with a detection idiom?

+2
source share
2 answers

Modify the detect class to allow variable arguments:

 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 hardcodes the void type:

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

Record Detector:

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

Check your class:

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

Demo

+2
source

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 is similar to working with your code. This can easily be expanded to support multi-parameter constructors using variation templates. I don’t know if this is a β€œuse of the discovery idiom,” but that is what I used myself once before.

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

+2
source

Source: https://habr.com/ru/post/1273971/


All Articles