Short version:
If I have function like:
constexpr bool has_some_property(Foo) { return true; }
Is there any way to invoke the function without having to actually instantiate Foo
? Say if Foo
is not default constructible?
Long winded version:
Anthony Williams recently wrote an article detailing a set of free functions enabled for any enum class
object that specialized a specific template. It follows a similar scheme in <ios>
, std::is_error_code
, where one specializes the template for a user defined type or value to allow enable_if
to enable some functions. In Anthony's case:
template<>
struct enable_bitmask_operators<my_bitmask>{
static constexpr bool enable=true;
};
And then when operators are defined:
template<typename E>
typename std::enable_if<enable_bitmask_operators<E>::enable,E>::type
operator|(E lhs,E rhs){
The problem with this technique is that the template specialization has to be in the same namespace as the original template, so this doesn't work:
namespace mystuff {
enum class Foo {
...
};
// Fail: wrong namespace
template<>
struct enable_bitmask_operators<Foo> : std::true_type {}
An alternative is to use a constexpr
function, which can be resolved in the same namespace as the class:
namespace mystuff {
enum class Foo {
...
};
constexpr bool enable_bitmask_operators(Foo) { return true; }
And then at definition:
template<typename E>
typename std::enable_if<enable_bitmask_operators(E()),E>::type
operator|(E lhs,E rhs){
The nice thing about this is that it work nicely even with nested classes. The problem with it is that it requires a default constructible class. That works fine for our enum class
example, but it doesn't work as a general solution to the issue of specialization. So if we imagine trying to use a constexpr
function instead of a template specialization for some other class we could get other failures:
struct Foo {
Foo() = delete;
};
constexpr bool has_some_property(Foo) { return true; }
...
// Fail for Foo...use of deleted function
template<typename E>
typename std::enable_if<has_some_property(E()),E>::type doStuff() {}
Its a little frustrating because I don't actually need that object to be created, I just want it there for ADL to identify the constexpr
function to call. I keep thinking there should be some way I can say that I want that function without having to actually create the object. I've played around with std::declval
but that doesn't work in this case.
Does anybody see a way around this quandary?
Just don't use constexpr
:
std::true_type has_some_property(Foo&& );
Does Foo
have it?
using has_it = decltype(has_some_property(std::declval<Foo>()));
static_assert(has_it::value, "It should!");
This is an unevaluated context, so we never have to call any Foo
constructor. And can sidestep the issues with constexpr
of requiring constant expressions.