I suppose you can use SFINAE together with the power of the comma operator
Following your idea, you can rewrite your f()
functions as follows
template <typename T, int = (T{}, 0)>
constexpr bool f (int)
{ return true; }
template <typename>
constexpr bool f (long)
{ return false; }
Observe the trick: int = (T{}, 0)
for the second template argument
This way f()
is enabled (power of the comma operator) only if T{}
can be constexpr constructed (because (T{}, 0)
is the argument for a template parameter), otherwise SFINAE wipe away the first version of f()
.
And observe that the fist version of f()
receive an unused int
where the second one receive a long
. This way the first version is preferred, when available, calling f()
with an int
; the second one is selected, as better than nothing solution, when the first one is unavailable (when the first template argument isn't constexpr default constructible).
Now you can construct two template constructors for foo
that you can alternatively enable/disable according the fact the template parameter T
(defaulted to A
) is or isn't constexpr constructible
template <typename T = A,
std::enable_if_t<f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "constexpr" << std::endl; }
template <typename T = A,
std::enable_if_t<not f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "not constexpr" << std::endl; }
The following is a full compiling example (C++14 or newer, but you can modify it for C++11):
#include <iostream>
#include <type_traits>
template <typename T, int = (T{}, 0)>
constexpr bool f (int)
{ return true; }
template <typename>
constexpr bool f (long)
{ return false; }
template <typename A>
struct foo
{
template <typename T = A,
std::enable_if_t<f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "constexpr" << std::endl; }
template <typename T = A,
std::enable_if_t<not f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "not constexpr" << std::endl; }
};
struct X1 { constexpr X1 () {} };
struct X2 { X2 () {} };
int main()
{
foo<X1> f1; // print "constexpr"
foo<X2> f2; // print "not constexpr"
}