How can I compile-time detect if a class has a constructor with a given signature? To be specific I would like to do the following:
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;
}
}
}
There are many sources for detecting functions with certain signatures. I am however unable to convert these to constructors. source 1 source 2 source 3, and more.
From sources I found I compiled the following to detect if a function has the plus operator:
template<typename T>
using HasUnarchiveConstructorImpl = decltype(std::declval<T>() + std::declval<T>());
template< typename T >
using HasUnarchiveConstructor = std::is_detected<HasUnarchiveConstructorImpl, T>;
How can I extend this to the check I want to perform? Or how can I do it in a different way?
How can I extend this to the check I want to perform?
You could use decltype(...)
on an T{...}
expression as follows:
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);
Or how can I do it in a different way?
See Howard Hinnant's answer.