Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this template metafunction involving std::enable_if yield undesired results?

Tags:

c++

templates

I have a type trait

template <typename T, typename Enable = void>
struct is_binary_function : std::false_type {};

and its specialization

template <typename function_t>
struct is_binary_function<function_t,
                          std::enable_if_t<
                              !std::is_void_v<typename function_t::result_t> &&
                              !std::is_void_v<typename function_t::parameter1_t> &&
                              !std::is_void_v<typename function_t::parameter2_t> &&
                              function_t::isBinaryCallable
                              , function_t>
        > : std::true_type {};

I am trying to identify classes, that have the public type definitions result_t, parameter1_t, and parameter2_t, as well as a static constant isBinaryCallable with the value true.

However, the following code does not output what I expect:

struct f {
    using result_t = float;

    using parameter1_t = float;
    using parameter2_t = float;

    static constexpr bool isBinaryCallable = true;
};


int main() {
    using function_t = f;

    std::cout << is_binary_function<f>::value << '\n'; //Error: outputs false, instead of true
    std::cout << std::is_void_v<function_t::result_t> << '\n'; //false, as expected
    std::cout << std::is_void_v<function_t::parameter1_t> << '\n'; //false, as expected
    std::cout << std::is_void_v<function_t::parameter2_t> << '\n'; //false, as expected
    std::cout << function_t::isBinaryCallable << '\n'; //true, as expected
    std::cout << (!std::is_void_v<typename function_t::result_t> &&
        !std::is_void_v<typename function_t::parameter1_t> &&
        !std::is_void_v<typename function_t::parameter2_t> &&
        function_t::isBinaryCallable) << '\n'; // true, as expected.
}

I guess my use of the metafunction pattern is flawed, but I can't figure out what I did wrong.

Why does the above metafunction not work as expected?

I am using Visual Studio 2017, set to the C++ 17 Standard.

like image 459
LukeG Avatar asked Jan 28 '23 13:01

LukeG


1 Answers

std::enable_if_t<
                          !std::is_void_v<typename function_t::result_t> &&
                          !std::is_void_v<typename function_t::parameter1_t> &&
                          !std::is_void_v<typename function_t::parameter2_t> &&
                          function_t::isBinaryCallable
                          , function_t>

should be

std::enable_if_t<
                          !std::is_void_v<typename function_t::result_t> &&
                          !std::is_void_v<typename function_t::parameter1_t> &&
                          !std::is_void_v<typename function_t::parameter2_t> &&
                          function_t::isBinaryCallable
                          , void>

or

std::enable_if_t<
                          !std::is_void_v<typename function_t::result_t> &&
                          !std::is_void_v<typename function_t::parameter1_t> &&
                          !std::is_void_v<typename function_t::parameter2_t> &&
                          function_t::isBinaryCallable>

because is_binary_function<f>::value is is_binary_function<f, void>::value as specified in your primary template specialization of is_binary_function (the second argument defaults to void), meanwhile

std::enable_if_t<
                          !std::is_void_v<typename function_t::result_t> &&
                          !std::is_void_v<typename function_t::parameter1_t> &&
                          !std::is_void_v<typename function_t::parameter2_t> &&
                          function_t::isBinaryCallable
                          , function_t>

when passed function_t as f is f, not void. So it fails to match.

like image 167
Yakk - Adam Nevraumont Avatar answered Feb 06 '23 16:02

Yakk - Adam Nevraumont