3

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?

1
  • 1
    Note that you may use Foo* instead of Foo. Commented Feb 10, 2015 at 10:49

3 Answers 3

10

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Ok, that's pretty sweet. l was hung up on having to have an overload for the false case as well, but we don't need that for SFINAE. So my final example works great with typename std::enable_if<decltype(has_some_property(declval<E>())::value,E>::type. Thanks!
0

Let me answer your first problem around enable_if trick instead:

#include <type_traits>

namespace LibBitmasks {
    template<typename E>
    struct is_bitmask: std::false_type {
    };
}

template<typename E>
typename std::enable_if<LibBitmasks::is_bitmask<E>::value, E>::type operator |(E lhs, E rhs) {
    return static_cast<E>(static_cast<typename std::underlying_type<E>::type>(lhs) |
                          static_cast<typename std::underlying_type<E>::type>(rhs));
}

namespace MyLib {
    enum class Q {
        Q1 = 1,
        Q2 = 2,
        Q3 = 3
    };
}

namespace LibBitmasks {
    template<>
    struct is_bitmask<MyLib::Q>: std::true_type {
    };
}

int main() {
    using MyLib::Q;
    return (Q::Q1 | Q::Q2) == Q::Q3 ? 0 : 42;
}

If you worry about global namespace pollution (more specifically, about potential conflicts with other operator | overloads) then you may hide it in LibBitmasks::ops namespace. Then whenever you want to use your operators, you just say using namespace LibBitmasks::ops and all the code will work the same way.

1 Comment

Yeah, it certainly works, but if I'm in the middle of a header with several declarations I either have to close the current namespace scope and restart it after the specialization or put my template specialization far away in the code. The ADL solution allows me to place the "is_bitmask" declaration immediately after the enum so it's easier to see the connection.
0

Seems like a simple problem: a function template can be made that takes no arguments. That way you don't need to create any values at all to call the function :)

You can use a function template, or a class template as well. The variants for C++11, C++14 and C++17 below have been chosen to provide the shortest type expressions while using the features available in the given C++ standard.

#include <type_traits>

struct Foo {
    Foo() = delete;
    Foo(bool) {}
};

// C++11
template <typename T> constexpr bool has_some_property1() { return false; }
template <> constexpr bool has_some_property1<Foo>() { return true; }

// C++11
template <typename T> struct has_some_property2 : std::false_type {};
template <> struct has_some_property2<Foo> : std::true_type {};

// C++17
template <typename T> constexpr bool has_some_property2_v = has_some_property2<T>::value;

template<typename E>  // C++11
typename std::enable_if<has_some_property1<E>(), E>::type doStuff1() { return {true}; }

template <typename E>  // C++14 (enable_if_t)
typename std::enable_if_t<has_some_property1<E>(), E> doStuff2a() { return {true}; } 
template <typename E>
typename std::enable_if_t<has_some_property2<E>::value, E> doStuff2b() { return {true}; } 

template <typename E>  // C++17 (..._v)
typename std::enable_if_t<has_some_property2_v<E>, E> doStuff2c() { return {true}; }

int main()
{
    doStuff1<Foo>();    // compiles
    doStuff2a<Foo>();   // compiles
    doStuff2b<Foo>();   // compiles
    doStuff2c<Foo>();   // compiles
    #if 0
    doStuff1<bool>();   // fails to compile
    doStuff2a<bool>();  // fails to compile
    doStuff2b<bool>();  // fails to compile
    doStuff2c<bool>();  // fails to compile
    #endif
}

2 Comments

Just a question: why return {true}; and not return true;?
Just to document that a "big" object is instantiated during the return.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.