em2er
em2er

Reputation: 881

Is there any method to implement something like std::is_integral_literal?

Suppose we have two functions:

//(1)
template<class T ,
         class = typename std::enable_if<std::is_integral<T>::value & ! is_integral_literal<T>::value>::type >
void foo(T)
{
}

and

//(2)
template<class T ,
         class = typename std::enable_if<is_integral_literal<T>::value>::type >
void foo(const T&)
{
}

so

int x;
foo(x); //calls (1)
foo(0); //calls (2)
foo(1000); //calls (2)

How can I implement is_integral_literal? I have made some workaround with operator "" _int_lit(long long) which gives me ability to express it with foo(0_int_lit), but may be there is another solution?

Upvotes: 3

Views: 134

Answers (1)

Tristan Brindle
Tristan Brindle

Reputation: 16834

One approach might be to use the fact that an integer literal is an rvalue? Then if your function signature is

template <typename T,
          typename = std::enable_if_t<std::is_integral<T>::value>>
T f(T&& t) {
    return t;
}

when called with an rvalue int (like a literal), T will be deduced as plain int, the enable_if condition will hold and this overload will be considered. But when called with an lvalue, for example

int i = 0;
f(i);

then T will be deduced as int&, in which case is_integral<int&>::value is false and SFINAE will kick in. You can then add a second overload like

template <typename T,
          typename = std::enable_if_t<std::is_integral<T>::value>>
T f(const T& t)
{
    return t;
}

to handle the lvalue case (when called with an rvalue both overloads will be considered, but the first will be a better match).

This doesn't quite fit the bill completely, as it's still possible to force the first overload with a non-literal by calling f(std::move(i)), but I don't know whether this would be a problem for your use-case.

Upvotes: 3

Related Questions