Search code examples
c++templateslambdac++17default-arguments

Using enable_if on a defaulted template argument for a constexpr lambda


I'm trying to write a generic function that will always return a -1. I want the template argument list to default to int. I'm trying to use std::enable_if or std::enable_if_t to test if the type T is a valid arithmetic type by using std::is_arithmetic or std::is_arithmetic_v. I'm having syntax issues to be able to get this to compile correctly. Here is what my lambda looks like:

template<typename T = int,
std::enable_if_t<std::is_arithmetic_v<T>> >
static constexpr T negative_one = [](){ 
    return static_cast<T>(-1); 
};

This is a very trivial function and concept, but the compiler wants to complain that the default argument is not at the end of the argument list... What would its proper definition look like?

This is how I would be using it:

{
    int i = negative_one();
    float f = negative_one<float>();
}

Solution

  • Use non-type optional template argument for sfinae. Your type needs to be a lambda type (not T) if you want to call it/pass it as a predicate. You can achieve this with automatic type deduction.

    template<typename T = int, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
    static constexpr auto negative_one = [](){ 
        return static_cast<T>(-1); 
    };
    

    Another option could be to use a function instead of a lambda:

    
    template<typename T = int, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
    static constexpr T negative_one() { 
        return static_cast<T>(-1); 
    };