passing lambda to void specified template fails - c++

i simplified the problem as much as i could so here is the function in question:
class Test
{
public:
template<class T>
void ExecuteFunction(std::function<void(T)> f)
{
}
};
if i call the function with int-typing everything works fine, however, if i call it with a void-typed lambda it doesn't compile anymore.
Test test;
test.ExecuteFunction<void>( // doesn't compile
[](void)->void
{
int i = 5;
});
test.ExecuteFunction<int>( // this compiles
[](int)->void
{
int i = 5;
});
Compiler errors:
Error C2672 'Test::ExecuteFunction': no matching overloaded function found
Error C2770 invalid explicit template argument(s) for 'void Test::ExecuteFunction(std::function<void(P)>)'
Error (active) no instance of function template "Test::ExecuteFunction" matches the argument list
is there a way around this? how would someone specify the template so that both calls work?

Sure, void in parentheses is but a vintage C-style sugar. You'll have to specialize your template:
template<> void Test::ExecuteFunction<void>(std::function<void()> f) {}
If that does not compile, well, you can use a helper template to encapsulate the type-selection:
#include <iostream>
#include <functional>
template<class T> struct callable {
using type = std::function<void(T)>;
};
template<class T> using callable_t =
typename callable<T>::type;
template<> struct callable<void> {
using type = std::function<void()>;
};
class Test
{
public:
template<class T>
void ExecuteFunction(callable_t<T> f) {}
};
int main() {
Test test;
test.ExecuteFunction<void>( // does compile
[](void)->void {});
test.ExecuteFunction<int>( // this compiles
[](int)->void {});
}
But be aware that this way you'll have to also do something to the arguments passing (in your example, a generic case's argument is unary yet specialization for void expects a nullary function object).

You can add an overload to the class like this:
// as before:
template<class T>
void ExecuteFunction(std::function<void(T)> f) {}
// new overload (not a template):
void ExecuteFunction(std::function<void()> f) {}
As you can't use type deduction anyhow, you can now explicitly call this function by not specifying any template parameter as follows.
Test test;
test.ExecuteFunction(
[](void)->void
{
int i = 5;
});

Is too late to play?
I propose another solution based on a custom type trait (with a specialization for void) that, given a T type, define the correct std::function type; i mean
template <typename T>
struct getFuncType
{ using type = std::function<void(T)>; };
template <>
struct getFuncType<void>
{ using type = std::function<void()>; };
This way your ExecuteFunction() simply become
template <typename T>
void ExecuteFunction (typename getFuncType<T>::type f)
{
}
If you want simplify a little the use of getFuncType, you can add a using helper to extract the type
template <typename T>
using getFuncType_t = typename getFuncType<T>::type;
so the ExecuteFunction() can be simplified as follows
template <typename T>
void ExecuteFunction (getFuncType_t<T> f)
{
}

Related

SFINAE not working with member function of template class

I have a template class where I would like to remove a member function if the type satisfies some condition, that, as far as I understand, should be a very basic usage of SFINAE, for example:
template<class T>
class A
{
public:
template<typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
T foo () {
return 1.23;
}
};
However, this is results in an error "no type named 'type'", like SFINAE was not going on. This however works if foo is a function not member of a class. What is wrong with this implementation?
You're missing a dependent name for the compiler to use for SFINAE. Try something like this instead:
#include <type_traits>
template<class T>
class A
{
public:
template<typename Tp = T>
typename std::enable_if<std::is_floating_point<Tp>::value, Tp>::type
foo () {
return 1.23;
}
};
int main() {
A<double> a;
a.foo();
}
If the type T is not floating point, the declaration would be malformed (no return type) and the function would not be considered for the overload set.
See it on godbolt.

Type deduction for template class taking a lambda

I am trying to write a class which is able to call a lambda with no arguments later in time. I was expecting C++17 class template argument deduction to avoid the need for a factory function. However, trying to instantiate an object without specifying the type fails. I am fine using the factory function but I would like to understand why this happens.
I am using VC++2017, with the C++17 toolset enabled. Is this expected behavior? Why? Can the factory function be avoided or is it needed due to different type deduction rules for template functions and template classes? Any help would be appreaciated.
template <typename F>
class WillInvoke
{
public:
WillInvoke(std::decay_t<F> f) : f(std::move(f)) { }
void CallNow() { f(); }
private:
std::decay_t<F> f;
};
template <typename F>
WillInvoke<F> make_WillInvoke(F && f)
{
return WillInvoke<F>(std::forward<F>(f));
}
int main()
{
// OK
auto w = make_WillInvoke([](){ std::cout << "Hello World"; });
w.CallNow();
// Won't compile
WillInvoke w2([](){ std::cout << "Hello World"; }); // No instance of constructor matches argument list
w2.CallNow();
}
This is because a member type alias like std::decay<T>::type is not deductible.
template<typename T>
void call_me(std::decay_t<T>) {}
// won't work :(
// call_me(1);
I don't think your class should decay the type. Instead, your class should state that it requires an object type and move the decay into the make function:
template <typename F> // requires std::is_object_v<F>
class WillInvoke
{
static_assert(std::is_object_v<F>,
"WillInvoke requires F to be an object type"
);
public:
WillInvoke(F f) : f(std::move(f)) { }
void CallNow() { f(); }
private:
F f;
};
template <typename F>
auto make_WillInvoke(F && f) -> WillInvoke<std::decay_t<F>>
{
return WillInvoke<std::decay_t<F>>(std::forward<F>(f));
}
The nice thing is that in C++20, you can uncomment the requires and let the compiler enforce that in the call site.

avoid pointer-to-member-function for non-class type

I am writing a kind of container class, for which I would like to offer an apply method which evaluates a function on the content of the container.
template<typename T>
struct Foo
{
T val;
/** apply a free function */
template<typename U> Foo<U> apply(U(*fun)(const T&))
{
return Foo<U>(fun(val));
}
/** apply a member function */
template<typename U> Foo<U> apply(U (T::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
struct Bar{};
template class Foo<Bar>; // this compiles
//template class Foo<int>; // this produces an error
The last line yields error: creating pointer to member function of non-class type ‘const int’. Even though I only instantiated Foo and not used apply at all. So my question is: How can I effectively remove the second overload whenever T is a non-class type?
Note: I also tried having only one overload taking a std::function<U(const T&)>. This kinda works, because both function-pointers and member-function-pointers can be converted to std::function, but this approach effectively disables template deduction for U which makes user-code less readable.
Using std::invoke instead helps, it is much easier to implement and read
template<typename T>
struct Foo
{
T val;
template<typename U> auto apply(U&& fun)
{
return Foo<std::invoke_result_t<U, T>>{std::invoke(std::forward<U>(fun), val)};
}
};
struct Bar{};
template class Foo<Bar>;
template class Foo<int>;
However, this won't compile if the functions are overloaded
int f();
double f(const Bar&);
Foo<Bar>{}.apply(f); // Doesn't compile
The way around that is to use functors instead
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return f(decltype(bar)(bar)); });
Which also makes it more consistent with member function calls
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return decltype(bar)(bar).f(); });
In order to remove the second overload you'd need to make it a template and let SFINAE work, e. g. like this:
template<typename T>
struct Foo
{
T val;
//...
/** apply a member function */
template<typename U, typename ObjT>
Foo<U> apply(U (ObjT::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
Alternatively, you could remove the second overload altogether, and use lambda or std::bind:
#include <functional> // for std::bind
template<typename T>
struct Foo
{
T val;
/** apply a member function */
template<typename U, typename FuncT>
Foo<U> apply(FuncT&& f)
{
return {f(val)};
}
};
struct SomeType
{
int getFive() { return 5; }
};
int main()
{
Foo<SomeType> obj;
obj.apply<int>(std::bind(&SomeType::getFive, std::placeholders::_1));
obj.apply<int>([](SomeType& obj) { return obj.getFive(); });
}
How can I effectively remove the second overload whenever T is a non-class type?
If you can use at least C++11 (and if you tried std::function I suppose you can use it), you can use SFINAE with std::enable_if
template <typename U, typename V>
typename std::enable_if<std::is_class<V>{}
&& std::is_same<V, T>{}, Foo<U>>::type
apply(U (V::*fun)() const)
{ return Foo<U>((val.*fun)()); }
to impose that T is a class.
Observe that you can't check directly T, that is a template parameter of the class, but you have to pass through a V type, a template type of the specific method.
But you can also impose that T and V are the same type (&& std::is_same<V, T>{}).

SFINAE and template function instantiation: Why a template argument cannot be deduced when used in function arguments with a SFINAE-enabled type?

I was experimenting with SFINAE these days, and something puzzles me. Why my_type_a cannot be deduced in my_function's instantiation?
class my_type_a {};
template <typename T>
class my_common_type {
public:
constexpr static const bool valid = false;
};
template <>
class my_common_type<my_type_a> {
public:
constexpr static const bool valid = true;
using type = my_type_a;
};
template <typename T> using my_common_type_t = typename my_common_type<T>::type;
template <typename T, typename V>
void my_function(my_common_type_t<T> my_cvalue, V my_value) {}
int main(void) {
my_function(my_type_a(), 1.0);
}
G++ gives me this:
/home/flisboac/test-template-template-arg-subst.cpp: In function ‘int main()’:
/home/flisboac/test-template-template-arg-subst.cpp:21:30: error: no matching function for call to ‘my_function(my_type_a, double)’
my_function(my_type_a(), 1.0);
^
/home/flisboac/test-template-template-arg-subst.cpp:18:6: note: candidate: template<class T, class V> void my_function(my_common_type_t<T>, V)
void my_function(my_common_type_t<T> my_type, V my_value) {}
^~~~~~~~~~~
/home/flisboac/test-template-template-arg-subst.cpp:18:6: note: template argument deduction/substitution failed:
/home/flisboac/test-template-template-arg-subst.cpp:21:30: note: couldn't deduce template parameter ‘T’
my_function(my_type_a(), 1.0);
^
What I expected was that, when calling my_function as I did in main, T would be deduced to the type of the function's first argument, and that type would be used in the function's instantiation. But it seems that my_common_type_t<T> is instantiated before the function, but even then, the type of my_cvalue would become my_type_a anyways, so I cannot see why this wouldn't work...
Is there a different way to do this? Should I just avoid two (or more) levels of template indirection?
Well, consider this:
template <>
struct my_common_type<int> {
constexpr static const bool valid = true;
using type = my_type_a;
};
template <>
struct my_common_type<double> {
constexpr static const bool valid = true;
using type = my_type_a;
};
// ...
int main(void) {
my_function(my_type_a{}, 1.0);
}
Does the compiler chooses my_common_type<int> or my_common_type<double>?
If the language would permit deduction in you case, it would have to match what T would be in my_common_type<T>::type in order to yield the exact type you send to the function parameter. Obviously, it's not only impossible, but with my example above, it may have multiple choices!
Fortunately, there is a way to tell the compiler that my_common_type<T> will always yield to T. The basics of the trick is this:
template<typename T>
using test_t = T;
template<typename T>
void call(test_t<T>) {}
int main() {
call(1);
}
What is T deduces to? int, easy! The compiler is happy with this kind of match. Also, since test_t cannot be specialized, test_t<soxething> is known to only be something.
Also, this is working too with multiple levels of aliases:
template<typename T>
using test_t = T;
template<typename T>
using test2_t = test_t<T>;
template<typename T>
void call(test2_t<T>) {}
int main() {
call(1); // will also work
}
We can apply this to your case, but we will need some tool:
template<typename T, typename...>
using first_t = T;
This is the same easy match as above, but we can also send some argument that will not be used. We will make sfinae in this unused pack.
Now, rewrite my_common_type_t to still be an easy match, whilst adding the constraint in the unused pack:
template <typename T>
using my_common_type_t = first_t<T, typename my_common_type<T>::type>;
Note that this is also working:
template <typename T>
using my_common_type_t = first_t<T, std::enable_if_t<my_common_type<T>::valid>>;
Now deduction will happen as expected! Live (GCC) Live (Clang)
Note that this trick will only work with C++14, as sfinae in this case (dropped parameters) is only guaranteed to happen since C++14.
Also note that you should either use struct for your trait, or use public: to make the member my_common_type<T>::type public, or else GCC will output a bogus error.

how to use enable_if with overloads

enum class enabler{};
template<typename T>
class X {
template<typename std::enable_if<std::is_class<T>::value,enabler>::type = enabler()>
void func();
void func(int a);
void func(std::string b);
};
I have this class with these 3 overloads for func. I need the second/third versions to be available for both class/non-class types, and the first version to be available only for class types. when I tried to use enable_if as above, the class instantiation for non-class types gives compile error.
For SFINAE to work, the template argument must be deduced. In your case, T is already known by the time you attempt to instantiate func, so if the enable_if condition is false, instead of SFINAE, you get a hard error.
To fix the error, just add a template parameter whose default value is T, and use this new parameter in the enable_if check. Now deduction occurs and SFINAE can kick in for non-class types.
template<typename U = T,
typename std::enable_if<std::is_class<U>::value,enabler>::type = enabler()>
void func();
And you don't really need a dedicated enabler type either, this works too
template<typename U = T,
typename std::enable_if<std::is_class<U>::value, int>::type* = nullptr>
void func();
I'm not really sure what you're going for with enabler here, but you can't do what you're trying because the declaration for your member function must be valid since T is not deduced by func. To achieve what you want in adding an extra overload, you can use some moderately contrived inheritance.
struct XBaseImpl {
// whatever you want in both versions
void func(int a) { }
void func(std::string b) { }
};
template <typename, bool> struct XBase;
// is_class is true, contains the extra overload you want
template <typename T>
struct XBase<T, true> : XBaseImpl {
static_assert(std::is_class<T>{}, ""); // just to be safe
using XBaseImpl::func;
void func() { } // class-only
};
// is_class is false
template <typename T>
struct XBase<T, false> : XBaseImpl { };
template<typename T>
class X : public XBase<T, std::is_class<T>{}> { };
You are not enabling or disabling something.
You simply want a compile time error in one specific case.
Because of that you don't require to rely on sfinae, a static_assert is enough.
As a minimal, working example:
#include<string>
template<typename T>
class X {
public:
void func() {
static_assert(std::is_class<T>::value, "!");
// do whatever you want here
}
void func(int a) {}
void func(std::string b) {}
};
int main() {
X<int> x1;
X<std::string> x2;
x2.func(42);
x2.func();
x1.func(42);
// compilation error
// x1.func();
}
Once a SO user said me: this is not sfinae, this is - substitution failure is always an error - and in this case you should use a static_assert instead.
He was right, as shown in the above example a static_assert is easier to write and to understand than sfinae and does its work as well.