I'm writing a template class that stores a std::function in order to call it later. Here is the simplifed code:
template <typename T>
struct Test
{
void call(T type)
{
function(type);
}
std::function<void(T)> function;
};
The problem is that this template does not compile for the void type because
void call(void type)
becomes undefined.
Specializing it for the void type doesn't alleviate the problem because
template <>
void Test<void>::call(void)
{
function();
}
is still incompatible with the declaration of call(T Type).
So, using the new features of C++ 11, I tried std::enable_if:
typename std::enable_if_t<std::is_void_v<T>, void> call()
{
function();
}
typename std::enable_if_t<!std::is_void_v<T>, void> call(T type)
{
function(type);
}
but it does not compile with Visual Studio:
error C2039: 'type' : is not a member of 'std::enable_if'
How would you tackle this problem?
Specialize the whole class:
template <>
struct Test<void>
{
void call()
{
function();
}
std::function<void()> function;
};
SFINAE doesn't work over (only) the template parameters of the class/structs.
Works over template methods whit conditions involving template parameters of the method.
So you have to write
template <typename U = T>
std::enable_if_t<std::is_void<U>::value> call()
{ function(); }
template <typename U = T>
std::enable_if_t<!std::is_void<U>::value> call(T type)
{ function(type); }
or, if you want to be sure that U is T
template <typename U = T>
std::enable_if_t< std::is_same<U, T>::value
&& std::is_void<U>::value> call()
{ function(); }
template <typename U = T>
std::enable_if_t<std::is_same<U, T>::value
&& !std::is_void<U>::value> call(T type)
{ function(type); }
p.s.: std::enable_if_t is a type so doesn't require typename before.
p.s.2: you tagged C++11 but your example use std::enable_if_t, that is C++14, and std::is_void_v, that is C++17
If you don't stick to use void, and your intention is to actually able to use Test without any parameters, then use variadic template:
template <typename ...T>
struct Test
{
void call(T ...type)
{
function(type...);
}
std::function<void(T...)> function;
};
This way, you can have any number of parameters. If you want to have no parameters, use this:
Test<> t;
t.call();
So this is not exactly the syntax you wanted, but there is no need for specialization, and this solution is more flexible, because supports any number of parameters.
Related
The following code does not work because the inferred template parameter F is std::tuple, whereas I want it to be Foo - the former takes two template parameters and the latter takes one.
#include <tuple>
template <typename T>
using Foo = std::tuple<int, T>;
template <template <typename> class F>
void foo(F<std::string> bar) {}
void test() {
foo(Foo<std::string>());
}
Is there any way to make type inference work with the using statement rather than turning Foo into it's own class?
#include <tuple>
template <typename T>
class Foo {
std::tuple<int, T> bar;
};
template <template <typename> class F>
void foo(F<std::string> bar) {}
void test() {
foo(Foo<std::string>());
}
More Info
I am using C++17's std::variant along with using to alias types that are generic on a single type and I would prefer to declare these with using statements rather than creating wrapper classes for each one. Something like this:
// Assuming Plus, Minus, etc all exist
template <typename T>
using Operation = std::variant<Plus<T>, Minus<T>, Times<T>>;
Building a Haskell-Style Functor
The point of this exercise is to build a small functor library loosely based on Haskell's functor typeclass. I have defined the "typeclass" like this:
template <template <typename> class F>
class Functor {
public:
template <typename T, typename U>
static F<U> fmap(std::function<U(T)> f, F<T> functor);
};
But I also wanted to add some sugar so that you can create a general mapper that will map a function over any function type without pre-specifying the functor type:
template <typename T, typename U>
struct FMap {
FMap(std::function<U(T)> f) : f_(f) {}
template <template <typename> class F>
F<U> operator()(F<T> functor) {
return Functor<F>::fmap(f_, functor);
}
private:
std::function<U(T)> f_;
};
template <typename T, typename U>
FMap<T, U> fmap(std::function<U(T)> f) {
return FMap<T, U>(f);
}
This works well with a simple value-wrapper functor:
template <typename T>
class Value {
public:
Value(T value) : value_(value) {}
const T& value() const {
return value_;
}
private:
T value_;
};
template <>
template <typename T, typename U>
Value<U> Functor<Value>::fmap(std::function<U(T)> f, Value<T> value) {
return Value<U>(f(value.value()));
}
void test() {
std::function<std::string(int)> fn = [](int x) {
return std::to_string(x);
};
auto result = fmap(fn)(Value(42));
// result.value() == "42"
}
Now I am trying to get it to work with a more complicated type that uses std::tuple or std::variant like in the above example.
template <>
template <typename T, typename U>
Foo<U> Functor<Foo>::fmap(std::function<U(T)> f, Foo<T> value) {
return Foo<U>(std::get<0>(value), f(std::get<1>(value)));
}
void test() {
std::function<std::string(int)> fn = [](int x) {
return std::to_string(x);
};
// This is the desirable syntax but it doesn't build
// fmap(fn)(Foo<int>(42, 7));
// This builds but it's super ugly
fmap(fn).operator()<Foo>(Foo<int>(42, 7));
}
Based on the response by SkepticalEmpiricist below, I am thinking that type aliases may not be the way to go here and instead I will have to introduce small wrapper classes - unless there is an SFINAE approach that would get this working.
This library is mostly a curiosity and a means for me to explore some more advanced template concepts - thanks for the help!
So first attempt before we start digging for some SFINAE based trickery to try circumvent the unavoidable:
Alias templates are never deduced by template argument deduction
We could "deduce" the template arguments for the compiler ourselves like this:
#include <tuple>
template <typename T>
using Foo = std::tuple<int, T>;
template <template <typename ...> class F, typename T, typename ...Ts>
void foo(F<T, std::string, Ts...> bar) {}
void test() {
foo(Foo<std::string>());
}
So now we have it compiling for your foo(Foo<std::string>()); call with Foo being the alias template over std::tuple and, more importantly, foo() is still specialized only for Foo<std::string>.
However, to support usage simultaneously of foo() for both the std::tuple alias template and the wrapper class for example, we still don't have it compiling error-free. As in, if we now comment-out the tuple-flavor Foo and bring back in the wrapper class Foo then calling our rewritten foo() will not compile.
To address the issue, let's give it a try with SFINAE to the rescue and replace the last declaration of foo() with this code:
template <template <typename ...> class F, typename T, typename ...Ts,
typename std::enable_if_t<std::is_same<F<T, Ts...>,
std::tuple<T, Ts...>>::value >* = nullptr>
void foo(F<T, std::string, Ts...> bar) {}
template <template <typename> class F>
void foo(F<std::string> bar) {}
Now you can call foo() for instances of both wrapper class of tuples and alias template for tuples. You could implement in the same fashion for std::variant as well.
With:
template <typename T> using Foo = std::tuple<int, T>;
template <template <typename> class F> void foo(F<std::string> bar) {}
void test() { foo(Foo<std::string>()); }
Foo<std::string> is std::tuple<int, std::string>.
so test is
void test() { foo(std::tuple<int, std::string>()); }
How do you expect compiler deduce from tuple from which alias it come ?
we might have
template <typename T> using Bar = std::tuple<int, std::string>;
template <typename T> using Bar2 = std::tuple<some_trait<T>::type, some_trait<T>::type2>;
// ...
A possible workaround might be:
template <typename T, typename U>
Foo<U> fmap(std::function<U(T)> f, Foo<T> value)
{
return Foo<U>(std::get<0>(value), f(std::get<1>(value)));
}
With calling syntax:
fmap(fn, Foo<int>(42, 7));
To determine if a function exists for a function, you can use the following:
template <typename...Ts>
using void_t = void;
void fn(int);
struct X {};
template <typename T, typename = void_t<decltype(fn(std::declval<T>()))>>
void fn2(T) { }
void test() {
fn2(int(1)); // works
//fn2(X()); // doesn't work
}
Now, is there a way of detecting if the fn(T) doesn't exist for type T?
Example:
void test2() {
//fn2(int(1)); // doesn't work
fn2(X()); // works
}
The reason for this is to define an exclusion operation so that I can define fn2() for both to avoid an ambiguity error.
The usual way of doing it is to make a type trait, as #chris said:
template <typename T, typename = void>
struct fn_callable_with : std::false_type {};
template <typename T>
struct fn_callable_with<T, void_t<decltype(fn(std::declval<T>()))>> : std::true_type {};
// For bonus C++14 points:
// template <typename T>
// /*C++17: inline*/ constexpr bool fn_callable_with_v = fn_callable_with<T>::value;
template <typename T, typename = typename std::enable_if<!fn_callable_with<T>::value>::type>
// C++14: template <typename T, typename = std::enable_if_t<!fn_callable_with_v<T>>>
void fn2(T) { }
You need another overload of fn2, otherwise SFINAE won't do anything useful.
void fn2(...) { } // called if the overload below is SFINAEd away
template <typename T, typename = void_t<decltype(fn(std::declval<T>()))>>
void fn2(T) { }
live example on wandbox
The idea is that SFINAE can remove candidates from an overload set. If fn2 is the only candidate, then you're going to get an hard error.
The code below doesn't compile, it complains about "can't convert string to int" when I call func with type Foo and "can't convert int to string" when I call func with type Bar. I thought I already used std::is_same to tell if the type is a Foo or Bar, why this seems to be not working? What would be a better way to do this?
class Foo {
Foo(int foo){}
};
class Bar {
Bar(string foo){}
};
template<typename T>
void func(){
if(std::is_same<T, Foo>::value) {
T t(1);
} else {
T t("aaa");
}
}
func<Foo>();
func<Bar>();
There is no static if in C++, so the code has to be compilable even if the branch is not taken.
You may solve that with specialization:
template<typename T>
void func(){
T t("aaa");
}
template<>
void func<Foo>(){
Foo t(1);
}
Demo
If you want a more general solution than the one proposed by Jarod42, you could use std::enable_if (since c++11):
template<typename T>
typename std::enable_if<std::is_constructible<T, int>::value, void>::type func() {
T t(1);
}
template<typename T>
typename std::enable_if<std::is_constructible<T, const char *>::value, void>::type func() {
T t("abc");
}
This way, the compiler will only generate function where enable_if is true (this is a "almost static if").
You can use std::enable_if to check a lot of things, if you only need to check if the instantiation T(1) is valid you could use SFINAE expressions:
template<typename T>
decltype(T(1), void()) func(){
T t(1);
}
template<typename T>
decltype(T(std::string()), void()) func() {
T t("abc");
}
See also std::is_constructible.
Tag dispatching is the way to go.
template<class T>
void func_impl( std::true_type T_is_Foo ) {
T t(1);
}
template<class T>
void func_impl( std::false_type T_is_Foo ) {
T t("aaa");
}
template<typename T>
void func(){
return func_impl( std::is_same<T,Foo>{} );
}
You can mess around with template function specialization or SFINAE; both are fragile. Template function specialization behaves unlike similar features elsewhere in C++, and SFINAE is impenetrable.
Another option in C++14 is to write a static if using lambdas. This is impenetrable, but at least isolated from your actual code:
struct do_nothing{ template<class...Ts> void operator()(Ts&&...){} };
template<class F_true, class F_false=do_nothing>
auto static_if( std::true_type, F_true&& f_true, F_false&& f_false = do_nothing{} ) {
return std::forward<F_true>(f_true);
}
template<class F_true, class F_false=do_nothing>
auto static_if( std::false_type, F_true&& f_true, F_false&& f_false = do_nothing{} ) {
return std::forward<F_false>(f_false);
}
template<typename T>
void func(){
static_if( std::is_same<T,Foo>{}, [&](auto&&){
T t(1);
}, [&](auto&&){
T t("abc");
})(1);
}
which at least looks like an if statement. static_if returns the second or third argument depending on the static truth value of its first argument.
In this case, we pass in lambdas. We then invoke the return value.
Only the lambda that matches the truth value of the first argument is invoked.
You could use SFINAE and create 2 overloaded functions for different T types
typename = std::enable_if<std::is_same<...>::value>::type
typename = std::enable_if_t<std::is_same<...>::value> // for c++14
template<typename T>
typename std::enable_if<std::is_same<Foo, T>::value>::type
func()
{
T t(4);
}
template<typename T>
typename std::enable_if<!std::is_same<Foo, T>::value>::type
func()
{
T t("4");
}
I have a template that has a function pointer as it's 2nd parameter and a type that the function pointer is dependent on as it's first.
i.e.
template <typename P, typename void(*fn)(P)>
auto function(P) -> otherType<P, fn>;
I want to make it so that I can just specify the function pointer in the template list without having to specify the dependent type as that type should somehow be able to be inferred from the function pointer that I specify (or maybe even the parameter list, but I think that it probably is too far down the line).
My first thought was to defer the conversion to a template parameter value, by passing a template typename and then convert to a value after the fact though template metaprogramming wizardry.
i.e.
template <typename F, typename P>
auto function(P) -> [[ something here to get otherType<P, fn> if F was a function pointer ]]
However, I'm not sure how I can do this. Any ideas?
Edit
What I'm trying to accomplish here is to make a helper function that will generate a class object. So, given what was said by StenSoft, this is what I've come up with. Unfortunately it doesn't work with a failure inside the main() function where it cannot match to the correct function due to deduction failure:
#include <iostream>
#include <functional>
template<typename T, typename F>
struct wrapper_fntor
{
T m_t;
F m_f;
wrapper_fntor(T t, F f) : m_t(t), m_f(f) {}
void invoke() { m_f(m_t); }
};
template<typename T, void(*fn)(T)>
struct wrapper_fn
{
T m_t;
wrapper_fn(T t) : m_t(t) {}
void invoke() { fn(m_t); }
};
template <typename T>
struct Wrapper;
template <typename Ret, typename P>
struct Wrapper<Ret(P)>
{
template <Ret(*fn)(P)>
static Ret function(P p)
{
return fn(std::forward<P>(p));
}
template <Ret(*fn)(P)>
static P get_param_type(P);
typedef decltype(get_param_type<Ret(P)>()) param_t;
};
template<typename F>
wrapper_fn<typename Wrapper<F>::param_t, &Wrapper<F>::function> make_wrapper(typename Wrapper<F>::param_t param)
{
return wrapper_fn<typename Wrapper<F>::param_t, &Wrapper<F>::function>(param);
}
template<typename F>
wrapper_fntor<typename Wrapper<F>::param_t, F> make_wrapper(typename Wrapper<F>::param_t param, F fntor)
{
return wrapper_fntor<typename Wrapper<F>::param_t, F>(param, fntor);
}
void function(int value)
{
std::cout << "function called " << value << std::endl;
}
int main()
{
auto x = make_wrapper<function>(3);
x.invoke();
}
demo
For a similar problem I have used a templated function inside a templated wrapper class and a macro (this actually works with any parameters and return type):
template <typename T>
struct Wrapper;
template <typename Ret, typename... Params>
struct Wrapper<Ret(Params...)>
{
template <Ret(*fn)(Params...)>
static Ret function(Params... params)
{
return fn(std::forward<Params>(params)...);
}
};
#define FUNCTION(fn) \
Wrapper<decltype(fn)>::function<fn>
Considering class templates, it is possible to provide template specializations for certain types of groups using type traits and dummy enabler template parameters. I've already asked that earlier.
Now, I need the same thing for function templates: I.e., I have a template function and want a specialization for a group of types, for example, all types that are a subtype of a class X. I can express this with type traits like this:
std::enable_if<std::is_base_of<X, T>::value>::type
I thought about doing it this way:
template <typename T, typename ENABLE = void>
void foo(){
//Do something
}
template <typename T>
void foo<T,std::enable_if<std::is_base_of<A, T>::value>::type>(){
//Do something different
}
However, this does not work since partial specialization is not allowed for function templates. So how to do it then? Maybe a default parameter with the type trait as type? But how does the code look like then?
Overloads:
void foo_impl(T, std::false_type);
void foo_impl(T, std::true_type);
foo(T t) { foo_impl(t, std::is_base_of<A, T>()); }
The closest to what you're asking is enable_if on the return type:
template<typename T> typename std::enable_if<std::is_same<T, int>::value>::type foo();
template<typename T> typename std::enable_if<std::is_same<T, char>::value>::type foo();
However, dispatching to a helper function or class is likely to be more readable and efficient.
Helper function:
template<typename T> void foo_helper(std::true_type);
template<typename T> void foo_helper(std::false_type);
template<typename T> void foo() { foo_helper(std::is_same<T, int>()); }
Helper class:
template<typename T, bool = std::is_same<T, int>::value> struct foo_helper {};
template<typename T> struct foo_helper<T, true> { static void foo(); };
template<typename T> struct foo_helper<T, false> { static void foo(); };
template<typename T> void foo() { foo_helper<T>::foo(); }
Do the actual implementation (partial specializations etc..) in class templates and write a small wrapper template function that does nothing but call a static function in your class templates.
Tried a few things and finally came up with the correct syntax myself - sorry for asking. I didn't know that enable_if has a second parameter. By using this parameter and a default value, it is possible.
Here is the answer
template<typename T>
void foo(typename std::enable_if<std::is_base_of<A, T>::value,int>::type ENABLER = 0){
std::cout << "T is a subclass of A!";
}
template<typename T>
void foo(typename std::enable_if<!std::is_base_of<A, T>::value,int>::type ENABLER = 0){
std::cout << "T is NOT a subclass of A";
}