Reputation: 881
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
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