My question is an extension of this question: How to use sfinae for selecting constructors?
In the previous question, the asker just wanted to selectively enable a single constructor. I would like to change the behaviour of the constructor depending on whether the class template parameter type is default-constructible - the best way that I can come up with to do this is to have two constructors with the same usage such that exactly one is enabled for every instantiation. My case is also different because neither version of the constructor would be a template function if I weren't trying to selectively enable with enable_if
(whereas in the linked question both versions of the constructor are templated on int otherN
).
The comments in the accepted answer to the above question led me to this site, which led me to create the following minimal example:
#include <iostream>
#include <type_traits>
namespace detail {
enum class enabler {};
enum class disabler {};
}
template <typename Condition>
using EnableIf = typename std::enable_if<Condition::value, detail::enabler>::type;
template <typename Condition>
using DisableIf = typename std::enable_if<!Condition::value, detail::disabler>::type;
template<typename T>
struct A {
T data;
// Valid if T is default-construtible; SFINAE otherwise
template<EnableIf<std::is_default_constructible<T>>...>
A() { std::cout << "Data defaulted" << std::endl; }
// Valid if T is *not* default-constructible; SFINAE otherwise
template<DisableIf<std::is_default_constructible<T>>...>
A() : data(0) { std::cout << "Data zeroed" << std::endl; }
};
// struct which is not default-constructible
struct B {
B() = delete;
B(int) {}
};
int main()
{
A<int> x; // int is default-constructible
A<B> y; // class B is not default-constructible
return 0;
}
I can compile this (with -std=c++11
) if I comment out the first constructor and the declaration of x or the second constructor and the declaration of y. I would like to do neither, but when I try that the compiler complains that there is no type named type
in std::enable_if<false, >
.
The answers to this question take another approach to a similar problem, but I don't understand the factors at play well enough to be able to combine the approaches into something which works.