#include <string>
#include <iostream>
#include <vector>
#include <type_traits>
namespace detail
{
template<class T, class = decltype(T::zero)>
std::true_type has_zero_impl(int);
template<class T>
std::false_type has_zero_impl(short);
}
template<class T>
using has_zero = decltype(detail::has_zero_impl<T>(0));
template<class T, class = has_zero<T>>
struct zero
{
constexpr static T get() { return T(); }
};
template<class T>
struct zero<T, std::true_type>
{
constexpr static auto get() -> decltype(T::zero)
{ return T::zero; }
};
Usage example:
template<>
struct zero<std::string>
{
static constexpr const char* get()
{ return "[Empty]"; }
};
struct foo
{
int m;
static constexpr int zero = 42;
};
int main()
{
std::cout << zero<int>::get() << "\n";
std::cout << zero<std::string>::get() << "\n";
std::cout << zero<foo>::get() << "\n";
}
Compact version w/o trait:
template<class T>
struct zero
{
private:
template<class X>
constexpr static decltype(X::zero) zero_impl(int)
{ return X::zero; }
template<class X>
constexpr static X zero_impl(short)
{ return X(); }
public:
constexpr static auto get()
-> decltype(zero_impl<T>(0))
{
return zero_impl<T>(0);
}
};
template<>
struct zero<std::string>
{
constexpr static const char* get()
{ return "[Empty]"; }
};