Template deduction fails for known argument - c++

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

Related

How to deal with template const and non-const parameters?

I have a Template function taking in const types such as:
template <class T, class U>
void process(const T& v1, const U& v2)
{
//do some things
verify(v1);
verify(v2);
}
Then the verify function checks the Type for T using if constexpr as follows:
(The function also returns the variable. I set it to auto for the purpose of this question)
template <class T>
auto verify(const T& t)
{
if constexpr (is_same_v<T, int>)
return t;
if constexpr (is_same_v<T, string>)
return t;
if constexpr (is_same_v<T, double*>)
return t;
else
static_assert(false, "Type not allowed");
}
if the type is not found it will trigger a compilation error.
This all works very fine but the problem is I would like to make v2 a non-const U& parameter. This triggers the static_assert and I don't know why. I also set all parameters in both functions to non-const but I still get the same error. All I really want is to pass the arguments by reference. Can anyone give me some hints? Thanks in advance.
This is one of those things you'd need to know.
The form you're looking for is
template <class T> auto verify(T&& t) {
The reason is that T can be const U, a const-qualified type. The double && is necessary for rvalue references.
You probably want std::is_same_v<std::remove_cv_t<T>>, ...
And to simply things:
template <class T> auto verify(T&& t)
{
using baseT = std::remove_cv_t<T>;
static_assert(is_same_v<baseT, int> ||
is_same_v<baseT, string> ||
is_same_v<baseT, double*>);
return t;
}
A better way of doing that would be to static_assert some type trait:
#include <string>
#include <type_traits>
template <class T, class... Y>
inline bool constexpr is_one_of =
(std::is_same_v<std::decay_t<T>, std::decay_t<Y>> || ...);
template <class T>
void verify() {
static_assert(is_one_of<T, int, std::string, double*>);
}
template <class T, class U>
void process(T const& v1, U const& v2) {
verify<T>();
verify<U>();
// ...
}

What does it mean when one says something is SFINAE-friendly?

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.

SFINAE: std::enable_if as function argument

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

Pass functions with unspecified parameters in C++11?

So I've got a function like this:
template <typename T>
bool and_map(vector<T> v, function<bool(T)> fn) { ... }
And I want to pass it a vector and a lambda function like this:
[](int cell){ return(cell != -1); }
But I get an error which says there is no instance of and_map which takes these parameters.
When I do this it works:
template <typename T>
bool and_map(vector<T> v, function<bool(int)> fn) { ... }
How can I get it to work without specifying the parameter type of the passed function?
Here is the correct way to accept a functor:
template <typename T, typename F>
bool and_map(vector<T> v, F fn) { ... }
Having a function declared as:
template <typename T>
bool and_map(std::vector<T> v, std::function<bool(T)> fn)
a compiler tries to deduce a template type parameter T based on both arguments. However, a lambda expression is not std::function<T>, hence the compiler raises an error. To workaround that one can make the context of a second parameter (with std::function<bool(T)>) non-deducible with an identity trick:
template <typename T> struct identity { using type = T; };
template <typename T>
bool and_map(std::vector<T> v, typename identity<std::function<bool(T)>>::type fn)
{
return {};
}
std::vector<int> v;
and_map(v, [](int cell){ return(cell != -1); });
so that type T will be deduced only based on the first argument, and then used to define the type of the second parameter.
DEMO

Confusing C++ Template

I am studying C++ Templates. Can someone plaese explain every bit of this piece of code
template <class T>
struct identity
{
typedef T type;
};
template <class T>
T&& forward(typename identity<T>::type&& a)
{
return a;
}
template <class T>
struct identity
{
typedef T type;
};
This part is defining a class template named identity that holds a public member typedef named type of the type you pass as the template argument. In your example there are no partial or explicit specializations so any type that is passed to identity is type.
template <class T>
T&& forward(typename identity<T>::type&& a)
{
return a;
}
forward is a function template taking an rvalue-reference to the type returned by identity<T>::type. The type returned by type (however obvious it may be) cannot be deduced by the compiler to be T (because the type is a dependent type), so you must explicitly specify the template argument for forward.
The rvalue-reference syntax && (for the return-type) also denotes what is (informally) referred to as a universal reference since the type T is a template argument. This means the return-type can bind to both rvalues and lvalues returned by the function.
The parameter type identity<T>::type&& is not a universal reference because the type returned is not a template parameter. This means the parameter can only accept rvalues. That will require us to move lvalues into the parameter to forward:
int main()
{
int n{0};
forward<int>(std::move(n));
}
And in the end we return the parameter a to the rvalue reference. Note however that returning the parameter to T&& won't work because a will have to be moved:
template <class T>
T&& forward(typename identity<T>::type&& a)
{
return std::move(a);
}
Otherwise return an lvalue-reference instead:
template <class T>
T& forward(typename identity<T>::type&& a)
{
return a;
}
Firstly, you need another specialization for my_forward to allow this call:
int a;
my_forward<int>(a);
So, specialize my_forward for references like this:
template <class T>
T&& my_forward(typename identity<T>::type& a)
{
return static_cast<T&&>(a);
}
But in this case, call for
int a;
my_forward<int&>(std::ref(a));
is ambiguous:
note: candidate function [with T = int &]
T&& my_forward(typename identity<T>::type&& a)
^
note: candidate function [with T = int &]
T&& my_forward(typename identity<T>::type& a)
^
To avoid it, you should use std::remove_reference instead of just identity:
template <class T>
T&& my_forward(typename std::remove_reference<T>::type&& a)
{
return static_cast<T&&>(a);
}
template <class T>
T&& my_forward(typename std::remove_reference<T>::type& a)
{
return static_cast<T&&>(a);
}