So, I'm following the example set by the code somewhere on this web page:
http://eli.thegreenplace.net/2014/sfinae-and-enable_if/
Here's what I have:
template<typename T>
void fun(const typename std::enable_if_t<std::is_integral<T>::value, T>& val) {
std::cout << "fun<int>";
}
template<typename T>
void fun(const typename std::enable_if_t<std::is_floating_point<T>::value, T>& val) {
std::cout << "fun<float>";
}
int main()
{
fun(4);
fun(4.4);
}
This way I would have to write:
fun<int>(4);
fun<double>(4.4);
How would I avoid that?
Compiler complains that it can't deduce the parameter T.
The examples are wrong, since T is in a non-deduced context. Unless you call the function like fun<int>(4);, the code won't compile, but this is probably not what the author intended to show.
The correct usage would be to allow T to be deduced by the compiler, and to place a SFINAE condition elsewhere, e.g., in a return type syntax:
template <typename T>
auto fun(const T& val)
-> typename std::enable_if<std::is_integral<T>::value>::type
{
std::cout << "fun<int>";
}
template <typename T>
auto fun(const T& val)
-> typename std::enable_if<std::is_floating_point<T>::value>::type
{
std::cout << "fun<float>";
}
DEMO
Also, the typenames in your code contradict your usage of std::enable_if_t.
Use either c++11:
typename std::enable_if<...>::type
or c++14:
std::enable_if_t<...>
How would that work in a constructor which doesn't have a return type though?
In case of constructors, the SFINAE condition can be hidden in a template parameter list:
struct A
{
template <typename T,
typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
A(const T& val)
{
std::cout << "A<int>";
}
template <typename T,
typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
A(const T& val)
{
std::cout << "A<float>";
}
};
DEMO 2
Alternatively, in c++20, you can use concepts for that:
A(const std::integral auto& val);
A(const std::floating_point auto& val);
To allow deduction you need a function parameter that is straightforwardly based on T. You then need to figure out where to put your enable_if (which indeed does not allow T to be deduced). Common options are on the return type or on an extra default parameter that you ignore.
Some good examples here: http://en.cppreference.com/w/cpp/types/enable_if
Related
How can I tell the compiler that U is equivalent to either std::vector<T> or T?
template<typename T, typename U> std::vector<T> foo(T t, U){return std::vector<T>{};}
I'm not sure if this is better or worse than your proposed solution, but you can try template specialization, which is similar to function overloading function overloading.
This would look like this
// Generic function
// UPDATE: you can ignore this function altogether and use the two overloads below
template<typename T, typename U> std::vector<T> foo(T t, U u) { // Do something}
// First specialization for the case of U == T
// UPDATE: this is an *overload*, not a specialization
template<typename T> std::vector<T> foo(T t, T u) { // Do something}
// Second specialization for the case of U == std::vector<T>
// UPDATE: this is an *overload*, not a specialization
template<typename T> std::vector<T> foo(T t, std::vector<T> u) { // Do something}
A possible downside of this approach is the possibility of repeating code, which violates the DRY principle.
As such, if your objective is to simply constraint your arguments without needing to change the function definition, then this answer may be better suited for such application.
Update: As #HolyBlackCat commented, my example was of overloading, and not of template specialization. I updated the text accordingly.
I would disable type deduction (by using depending type) on second argument and provided two overloads.
namespace me {
// c++20 has this, so putting that in own namespace to cover older standards
template<typename T>
strut identity {
using type = T;
};
template<typename T>
using identity_t = typename identityT<>::type;
}
template<typename T>
std::vector<T> foo(T t, const std::vector<me::indentity_t<T>>& v) {
auto copy = v;
copy.push_back(t);
return copy;
}
template<typename T>
std::vector<T> foo(T t, me::indentity_t<T> v) {
return { v, t };
}
I found a solution by myself.
It seems could be achieved by std::enable_if. Is there any better way?
#include <iostream>
#include <vector>
template<typename T, typename U, typename = typename std::enable_if<
std::is_same< T, U >::value || std::is_same<std::vector<T>, U>::value>::type>
std::vector<int> foo()
{
std::cout << "on the move!\n";
return {};
}
int main()
{
foo<int, int>();
foo<int, std::vector<int>>();
//foo<int, float>(); //does not compile, in expectation.
}
A better/harder example:
#include <iostream>
#include <vector>
#include <functional>
template<typename T, typename U, typename = typename std::enable_if<
std::is_same< T, U >::value || std::is_same<std::vector<T>, U>::value>::type>
void foo(std::function<U(void)> func)
{
std::cout << "on the move!\n";
}
int main()
{
foo<int>(std::function<int(void)>());
foo<int>(std::function<std::vector<int>(void)>());
//foo<int>(std::function<float(void)>()); //does not compile, in expectation.
}
I asked this question and got a good answer but there is a one more not clear point about template parameter deduction in g++ with c++17 flag.
If we will take this code:
#include <iostream>
#include <vector>
template<class T, class A>
void func(const std::vector<T, A>&v)
{
std::cout << 1 << std::endl;
}
template<typename T, typename A, template <typename, typename>class Vector>
void func(const Vector<T, A>&v)
{
std::cout << 2 << std::endl;
}
void f()
{
std::vector<int> v;
func(v);
}
int main()
{
f();
return 0;
}
Difference in declaration of second template function.
In this case accordingly the answer template parameter deduction should be the same as before. But compiler not report about any ambiguity.
Previous version of second function which produce ambiguity error:
template<typename T, template <typename>class Vector>
void func(const Vector<T>&v)
{
std::cout << 2 << std::endl;
}
What I'm missing in this case?
With this new set of overloaded functions:
template<class T, class A>
void func(const std::vector<T, A>&v)
template<typename T, typename A, template <typename, typename>class Vector>
void func(const Vector<T, A>&v);
The first overload is more specialized than the second: the template parameters T,A,Vector of the second overload can be deduced if we passed an argument of type std::vector<P1,P2> where P1 and P2 are two invented types.
While with the previous set of overload:
template<class T, class A>
void func(const std::vector<T, A>&v);
template<typename T, template <typename>class Vector>
void func(const Vector<T>&v);
Neither of the two overloads are more specialized than the other. Because the previously described template argument deduction is not realizable.
The ranking of template function is described here.
Consider following code
template<typename T>
T modify(const T& item, std::function<T(const T&)> fn)
{
return fn(item);
}
When trying to use it as modify(5, [](const int& i){return 10*i;}); it fails to compile with
could not deduce template argument for 'std::function<T(const T &)> from lambda
I know that compiler can not deduce T from lambda, because lambda is not std::function, but isn't T already deduced from 5?
I can get over it using
template<typename T, typename F>
T modify(const T& item, const F& functor)
{
return functor(item);
}
for which previous example compiles, but it is in my opinion less intuitive. Is there a way to let the function argument to remain std::function and have it's template argument deduced automatically from item?
What you basically want to do is prevent deduction from happening. If template deduction occurs, it will fail (because a lambda is not a std::function<> - it doesn't matter that T was deduced from the first argument, deduction must succeed in every argument that is a deduced context). The way to prevent deduction is to stick the entire argument in a non-deduced context, the easiest way of doing that is to throw the type into a nested-name-specifier. We create such a type wrapper:
template <class T> struct non_deduce { using type = T; };
template <class T> using non_deduce_t = typename non_deduce<T>::type;
And then wrap the type in it:
template<typename T>
void foo(const T& item, std::function<void(T)> f);
template<typename T>
void bar(const T& item, non_deduce_t<std::function<void(T)>> f);
foo(4, [](int ){} ); // error
bar(4, [](int ){} ); // ok, we deduce T from item as int,
// which makes f of type std::function<void(int)>
Note, however, that:
template <typename T, typename F>
void quux(const T&, F );
is not really any less readable, and strictly more performant.
You can do it by using the identity trick as below:
template <typename T>
struct identity {
typedef T type;
};
template<typename T>
T modify(const T& item, typename identity<std::function<T(const T&)>>::type fn) {
return fn(item);
}
Live Demo
I can't clearly get the grasp of what it means when one mentions that a particular function, struct or ... is SFINAE-friendly.
Would someone please explain it?
When it allows substitution failure without hard error (as static_assert).
for example
template <typename T>
void call_f(const T& t)
{
t.f();
}
The function is declared for all T, even those which don't have f, so you cannot do SFINAE on call_f<WithoutF> as the method does exist. (Demo of non compiling code).
With following change:
template <typename T>
auto call_f(const T& t) ->decltype(t.f(), void())
{
t.f();
}
The method exists only for valid T.
so you can use SFINAE as
template<typename T>
auto call_f_if_available_impl(const T& t, int) -> decltype(call_f(t))
{
call_f(t);
}
template<typename T>
auto call_f_if_available_impl(const T& t, ...)
{
// Do nothing;
}
template<typename T>
auto call_f_if_available(const T& t)
{
call_f_if_available_impl(t, 0);
}
Note the int = 0 and ... is to order the overload.
Demo
--
An other case is when the template add special parameter to apply SFINAE for specialization:
template <typename T, typename Enabler = void> struct S;
And then
// Specialization only available for T which respect the traits.
template <typename T>
struct S<T, std::enable_if_t<my_type_trait<T>::value>>
{
};
An entity is termed SFINAE-friendly if it can be used in the context of SFINAE without producing a hard error upon substitution failure. I assume you already know what SFINAE is, as that is a whole other question in itself.
In the context of C++ standardization, the term SFINAE-friendly has so far been applied to std::result_of and std::common_type. Take the following example:
template <typename T>
void foo(T x, typename std::common_type<T, int>::type y) {}
void foo(std::string x, std::string y) {}
int main()
{
foo(std::string("hello"), std::string("world"));
}
Without SFINAE-friendly common_type, this would fail to compile, because std::common_type<std::string, int>::type would produce a hard error during template argument substitution. With the introduction of SFINAE-friendly common_type (N3843) this example becomes well-formed, because std::common_type<std::string, int>::type produces a substitution failure so that overload is excluded from the viable set.
Here's a similar example with result_of:
template <typename T>
auto bar(T f) -> typename std::result_of<T()>::type { return f(); }
void bar(int n) {}
int main()
{
bar(42);
}
Without SFINAE-friendly result_of, this would fail to compile, because std::result_of<int()>::type would produce a hard error during template argument substitution. With the introduction of SFINAE-friendly result_of (N3462) this example becomes well-formed, because std::result_of<int()>::type produces a substitution failure so that overload is excluded from the viable set.
Suppose I have a template function:
template<typename T>
void f(T t)
{
...
}
and I want to write a specialization for all primitive integer types. What is the best way to do this?
What I mean is:
template<typename I where is_integral<I>::value is true>
void f(I i)
{
...
}
and the compiler selects the second version for integer types, and the first version for everything else?
Use SFINAE
// For all types except integral types:
template<typename T>
typename std::enable_if<!std::is_integral<T>::value>::type f(T t)
{
// ...
}
// For integral types only:
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type f(T t)
{
// ...
}
Note that you will have to include the full std::enable_if return value even for the declaration.
C++17 update:
// For all types except integral types:
template<typename T>
std::enable_if_t<!std::is_integral_v<T>> f(T t)
{
// ...
}
// For integral types only:
template<typename T>
std::enable_if_t<std::is_integral_v<T>> f(T t)
{
// ...
}
I would use overload resolution. That spares you from having to use the gross SFINAE hack. Unfortunately there are many areas where you can't avoid it, but this fortunately isn't one of those.
template<typename T>
void f(T t)
{
f(t, std::is_integral<T>());
}
template<typename T>
void f(T t, std::true_type)
{
// ...
}
template<typename T>
void f(T t, std::false_type)
{
// ...
}
Using c++11, std::enable_if ( http://en.cppreference.com/w/cpp/types/enable_if ) can be used to do that:
template<typename T, class = typename std::enable_if<std::is_integral<T>::value>::type>
void f(T t) {...}
You can use a helper template that you can specialize like this:
#include <string>
#include <iostream>
#include <type_traits>
template <typename T, bool = std::is_integral<T>::value>
struct Foo {
static void bar(const T& t) { std::cout << "generic: " << t << "\n"; }
};
template <typename T>
struct Foo<T, true> {
static void bar(const T& t) { std::cout << "integral: " << t << "\n"; }
};
template <typename T>
static void bar(const T& t) {
return Foo<T>::bar(t);
}
int main() {
std::string s = "string";
bar(s);
int i = 42;
bar(i);
return 0;
}
output:
generic: string
integral: 42
Here is C++20 solution
template<std::integral T>
void f(T v) {
...
}
I think It's actually overloaded function but works the same.
What about a more straightforward and better readable way by just implementing the different versions inside the function body?
template<typename T>
void DoSomething(T inVal) {
static_assert(std::is_floating_point<T>::value || std::is_integral<T>::value, "Only defined for float or integral types");
if constexpr(std::is_floating_point<T>::value) {
// Do something with a float
} else if constexpr(std::is_integral<T>::value) {
// Do something with an integral
}
}
You dont have to worry about performance. The conditions are compile time constant and a descent compiler will optimize them away.
"if constexpr" is c++17 unfortunately but you may remove "constexpr" when both versions compile without errors for both types