I'm trying to create a trait that detects whteher type Apply has a valid result when called with 2 arguments. I would expect the static_assert in the code not to hit because the result of apply is a valid one (dividing float). Why does this assert hit, and how would I change the trait in such a way that all the valid overloads for apply are detected as true_type or constexpr bool true.
#include <type_traits>
#include <functional>
struct Apply
{
template<typename T1, typename T2>
float apply(const T1& a, const T2& b) const
{
return a / b;
}
};
struct ApplyInvoker
{
Apply a;
template<typename... Args>
auto operator()(Args&&... args)
{
return a.apply(std::forward<Args>(args)...);
}
};
template <class Void, class... T>
struct ValidCall : std::false_type
{
};
template <class... T>
struct ValidCall<
std::void_t<decltype(std::invoke(std::declval<ApplyInvoker>(), std::declval<T>()...))>,
T...>
: std::true_type
{
};
template<typename T1, typename T2>
constexpr bool CanApply = ValidCall<void, T1, T2>::value;
int main()
{
static_assert(CanApply<float, float>);
}
You're using your template as:
template<typename T1, typename T2>
constexpr bool CanApply = ValidCall<T1, T2>::value;
But the primary is declared as:
template <class Void, class... T>
struct ValidCall;
That first template parameter is named Void because it has to be void - that's what the specialization is matching against. So you have to do it this way:
template<typename T1, typename T2>
constexpr bool CanApply = ValidCall<void, T1, T2>::value;
// ^~~~
But also, this is C++17, and we have a type trait for that:
template<typename T1, typename T2>
constexpr bool CanApply = std::is_invocable_v<ApplyInvoker, T1, T2>;
The problem is that neither Apply nor ApplyInvoker actually work with type traits. Apply advertises itself as being invocable with any two arguments - there is no way to detect otherwise. ApplyInvoker advertises itself as being invocable with any number of arguments - but in a way that will lead to a hard compiler error if you try to find out with the wrong set of them. Both these types are what we would call SFINAE-unfriendly - they're not friendly to type traits, they're not testable.
If you want them to actually be testable, then you need to rewrite both as follows:
struct Apply
{
template<typename T1, typename T2>
float apply(const T1& a, const T2& b) const
-> decltype(float(a / b))
{
return a / b;
}
};
struct ApplyInvoker
{
Apply a;
template <typename... Args>
auto operator()(Args&&... args)
-> decltype(a.apply(std::forward<Args>(args)...)
{
return a.apply(std::forward<Args>(args)...);
}
};
Or something similar.
Related
Currently I'm looking for some way to get the parameter types of an overloaded member function by argument count and instance type.
In my case we know the name, the return type (void) and the argument count.
In addition there can't be a second overload with the same argument count and the functions are never cv nor ref qualified.
A sample:
#include <tuple>
#include <type_traits>
#include <iostream>
class TupleLikeType{
public:
void Deconstruct(int& a, char& b){
a = 12;
b = 'A';
}
void Deconstruct(int& a, char& b, bool& c){
Deconstruct(a, b);
c = true;
}
};
template<typename Type, std::size_t ArgCount>
class TupleDeconstructTypes{
public:
using type =
//to implement
std::conditional_t<ArgCount == 2,
std::tuple<int&, char&>, std::tuple<int&, char&, bool&>
>
//to implement end
;
};
template<typename T>
class DeconstructAdapter
{
private:
T& obj;
public:
template<
typename DepT = T
, typename... Args
>
constexpr void operator()(Args&&... args)
{
return obj.Deconstruct(std::forward<Args>(args)...);
}
public:
constexpr DeconstructAdapter(T& toDeconstruct) : obj(toDeconstruct)
{
}
};
template<typename Tuple>
class TupleWithOutRefs{};
template<template <typename...> typename Tuple, typename... T>
class TupleWithOutRefs<Tuple<T...>>{
public:
using type = Tuple<std::remove_reference_t<T>...>;
};
template<
std::size_t ArgCount
,typename T
,typename Args = typename TupleDeconstructTypes<T, ArgCount>::type
,typename TempTuple = typename TupleWithOutRefs<Args>::type
>
auto CreateTuple(T& t){
auto adapter = DeconstructAdapter(t);
TempTuple result{};
//std::apply calls std::invoke
//during this call all out-references are bound to our allocated stack memory
std::apply(adapter, result);
return result;
}
int main(){
//usage
static_assert(std::is_same_v<
TupleDeconstructTypes<TupleLikeType, 2>::type,
std::tuple<int&, char&>
>);
TupleLikeType t;
auto tuple = CreateTuple<2>(t);
std::cout << std::get<0>(tuple);
}
Do you have any idea to solve this in a generic way?
With limited number, you can do something like:
template <std::size_t Size>
struct helper;
template <>
struct helper<0>
{
template <typename C>
std::tuple<> operator() (void (C::*) ()) const;
};
template <>
struct helper<1>
{
template <typename C, typename T1>
std::tuple<T1> operator() (void (C::*) (T1)) const;
};
template <>
struct helper<2>
{
template <typename C, typename T1, typename T2>
std::tuple<T1, T2> operator() (void (C::*) (T1, T2)) const;
};
template <>
struct helper<3>
{
template <typename C, typename T1, typename T2, typename T3>
std::tuple<T1, T2, T3> operator() (void (C::*) (T1, T2, T3)) const;
};
// ...
template<typename Type, std::size_t ArgCount>
using TupleDeconstructTypes = decltype(helper<ArgCount>{}(&Type::Deconstruct));
Demo
I have a typelist. I would like to create a tuple with the results of calling a function on each type in that list and then use that as arguments to another functor. So something like this:
template<typename F>
struct function_traits;
template<typename T, typename R, typename... Args>
struct function_traits<R(T::*)(Args...) const> {
using return_type = R;
using param_types = std::tuple<Args...>;
};
template<typename T> struct function_traits : public
function_traits<decltype(&T::operator())> {};
template <typename T>
T* get_arg(int id)
{
// Actual implementation omitted. Uses the id parameter to
// do a lookup into a table and return an existing instance
// of type T.
return new T();
}
template <typename Func>
void call_func(Func&& func, int id)
{
using param_types = function_traits<Func>::param_types>;
func(*get_arg<param_types>(id)...); // <--- Problem is this line
}
call_func([](int& a, char& b) { }, 3);
The problem is that func(*get_arg<param_types>(id)...); doesn't actually compile since param_types is a tuple and not a parameter pack. The compiler generates this error: "there are no parameter packs available to expand". What I would liked to have happened is for that line to expand to:
func(*get_arg<int>(id), *get_arg<char>(id));
And to have that work for any number of arguments. Is there any way to get that result?
This question seems similar but does not solve my problem by itself: "unpacking" a tuple to call a matching function pointer. I have a type list and from that I want to generate a list of values to use as function arguments. If I had the list of values I could expand them and call the function as outlined in that question, but I do not.
Not sure that is what do you want.
I don't know how to expand, inside call_func(), the parameters pack of params_type but, if you afford the use of a helper struct and a compiler with C++14...
I've prepared the following example with support for return type.
#include <tuple>
template<typename F>
struct function_traits;
template<typename T, typename R, typename... Args>
struct function_traits<R(T::*)(Args...) const> {
using return_type = R;
using param_types = std::tuple<Args...>;
};
template<typename T> struct function_traits : public
function_traits<decltype(&T::operator())> {};
template <typename T, typename ... Args>
T get_arg (std::tuple<Args...> const & tpl)
{ return std::get<typename std::decay<T>::type>(tpl); }
template <typename ...>
struct call_func_helper;
template <typename Func, typename Ret, typename ... Args>
struct call_func_helper<Func, Ret, std::tuple<Args...>>
{
template <typename T, typename R = Ret>
static typename std::enable_if<false == std::is_same<void, R>::value, R>::type
fn (Func const & func, T const & t)
{ return func(get_arg<Args>(t)...); }
template <typename T, typename R = Ret>
static typename std::enable_if<true == std::is_same<void, R>::value, R>::type
fn (Func const & func, T const & t)
{ func(get_arg<Args>(t)...); }
};
template <typename Func,
typename T,
typename R = typename function_traits<Func>::return_type>
R call_func (Func const & func, T const & id)
{
using param_types = typename function_traits<Func>::param_types;
return call_func_helper<Func, R, param_types>::fn(func, id);
}
int main()
{
call_func([](int const & a, char const & b) { }, std::make_tuple(3, '6'));
return 0;
}
Hope this helps.
I would like to create a compile-type function that, given any callable object f (function, lambda expression, function object, ...) and a type T, evaluates to true, if f can be called with an argument of type T, and false if it cannot.
Example:
void f1(int) { ... }
void f2(const std::string&) { ... }
assert( is_callable_with<int>(f1));
assert(!is_callable_with<int>(f2));
I'm thinking that a clever use of the SFINAE rule could achieve this. Possibly somehow like this:
template<typename T, typename F>
constexpr bool is_callable_with(F&&, typename std::result_of<F(T)>::type* = nullptr) {
return true;
}
template<typename T, typename F>
constexpr bool is_callable_with(F&&) {
return false;
}
But this doesn't work, because if F is callable with T, both overloads participate in the overload resolution and there is an ambiguity. I'd like to rewrite it so in the positive case, the first overload would be picked by the overload resolution over the second one. Not sure if I'm even on the right track here though.
A variant of Paul's answer, but following the standard SFINAE test pattern. Again a generic trait with arbitrary parameter types A...:
struct can_call_test
{
template<typename F, typename... A>
static decltype(std::declval<F>()(std::declval<A>()...), std::true_type())
f(int);
template<typename F, typename... A>
static std::false_type
f(...);
};
template<typename F, typename... A>
using can_call = decltype(can_call_test::f<F, A...>(0));
Then a constexpr function as you requested:
template<typename T, typename F>
constexpr bool is_callable_with(F&&) { return can_call<F, T>{}; }
Check live example.
This will work with functions, lambda expressions, or function objects with arbitrary number of arguments, but for (pointers to) member functions you'll have to use std::result_of<F(A...)>.
UPDATE
Below, can_call has the nice "function signature" syntax of std::result_of:
template<typename F, typename... A>
struct can_call : decltype(can_call_test::f<F, A...>(0)) { };
template<typename F, typename... A>
struct can_call <F(A...)> : can_call <F, A...> { };
to be used like this
template<typename... A, typename F>
constexpr can_call<F, A...>
is_callable_with(F&&) { return can_call<F(A...)>{}; }
where I've also made is_callable_with variadic (I can't see why it should be limited to one argument) and returning the same type as can_call instead of bool (thanks Yakk).
Again, live example here.
I would make a type trait first:
template<class X = void>
struct holder
{
typedef void type;
};
template<class F, class T, class X = void>
struct is_callable_with_trait
: std::false_type
{};
template<class F, class T>
struct is_callable_with_trait<F, T, typename holder<
decltype(std::declval<F>()(std::declval<T>()))
>::type>
: std::true_type
{};
And then if you want, you can turn it into a function:
template<typename T, typename F>
constexpr bool is_callable_with(F&&)
{
return is_callable_with_trait<F&&, T>::value;
}
template<class F, class T, class = void>
struct is_callable_with_impl : std::false_type {};
template<class F, class T>
struct is_callable_with_impl<F,T,
typename std::conditional<
true,
void,
decltype( std::declval<F>() (std::declval<T>()) ) >::type
> : std::true_type {};
template<class T, class F>
constexpr bool is_callable_with(F &&)
{
return is_callable_with_impl< F, T >::value;
}
It is basically the same solution as the one posted by Paul, I just prefer to use conditional<true, void, decltype( ... ) > instead of an holder class to avoid namespace pollution.
This question follows this one : Function overloading and template deduction priority
Considering the following classes :
template<typename T1, typename T2>
class Base {};
class Derived0 : public Base<double, double> {};
template<typename T1, typename T2, typename T3>
class Derived1 : public Base<T1, T2> {};
template<typename T1, typename T2, typename T3, typename T4>
class Derived2 : public Base<T3, T4> {};
And the following functions :
template<typename T> f(const T& x); // version A
template<typename T1, typename T2> f(const Base<T1, T2>& x); // version B
My problem is that f(double) will call version A (ok), f(Base<double, double>) will call version B (ok), but f(Derived1<double, double, double>) will call version A (see the link to the other question at the beginning).
Using C++11, how to block version A and force version B for all derived members of Base<T1, T2> whatever T1 and T2 are ?
Note : If possible, I would like to avoid to add helper classes and prefer adding members to the provided classes.
Here's a trait that might work for you.
The trait class:
#include <type_traits>
template <typename, typename> struct Base { };
template <typename T> struct isbase
{
typedef char yes;
typedef yes no[2];
template <typename U, typename V> static yes & test(Base<U, V> const &);
static no & test(...);
static bool const value = sizeof(test(std::declval<T>())) == sizeof(yes);
};
Application:
#include <iostream>
template <typename T>
typename std::enable_if<!isbase<T>::value>::type f(T const &)
{
std::cout << "f(T const &)\n";
}
template <typename T1, typename T2>
void f(Base<T1, T2> const &)
{
std::cout << "f(Base<T1, T2> const &)\n";
}
Example:
template<typename T1, typename T2, typename T3>
struct Derived1 : public Base<T1, T2> {};
int main()
{
std::cout << isbase<double>::value << std::endl;
std::cout << isbase<Base<int, char>>::value << std::endl;
std::cout << isbase<Derived1<bool, bool, bool>>::value << std::endl;
f(double{});
f(Base<int, char>{});
f(Derived1<bool, float, long>{});
}
Generalization: We can make a more general trait to check if a type derives from a template instance:
template <typename T, template <typename...> class Tmpl>
struct derives_from_template
{
typedef char yes;
typedef yes no[2];
template <typename ...Args> static yes & test(Tmpl<Args...> const &);
static no & test(...);
static bool const value = sizeof(test(std::declval<T>())) == sizeof(yes);
};
Usage: derives_from_template<T, Base>::value etc.
I think you can give you B class template a marker type as member and cause instantiation of the general tempkate to fail when present. Normally, SFINAE works the other way around but using an indirection it should still work.
template<typename T1, typename T2>
class Base {
public:
struct isBase {};
};
template <typename T>
struct is_base {
template <typename S> char (&test(typename S::isBase*))[1];
template <typename S> char (&test(...))[2];
enum { value = sizeof(test<T>(0)) == 1 };
};
template <typename T>
typename std::enable_if<!is_base<T>::value>::type f(T value) {
...
};
The solution basically does something similar to KerrekSB's solution but doesn't require explicit spelling out the supported types: It uses the tag isBasd (which should probably be spelled more unique) to detect objects of type Base or derived.
I want to write a simple adder (for giggles) that adds up every argument and returns a sum with appropriate type.
Currently, I've got this:
#include <iostream>
using namespace std;
template <class T>
T sum(const T& in)
{
return in;
}
template <class T, class... P>
auto sum(const T& t, const P&... p) -> decltype(t + sum(p...))
{
return t + sum(p...);
}
int main()
{
cout << sum(5, 10.0, 22.2) << endl;
}
On GCC 4.5.1 this seems to work just fine for 2 arguments e.g. sum(2, 5.5) returns with 7.5. However, with more arguments than this, I get errors that sum() is simply not defined yet. If I declare sum() like this however:
template <class T, class P...>
T sum(const T& t, const P&... p);
Then it works for any number of arguments, but sum(2, 5.5) would return integer 7, which is not what I would expect.
With more than two arguments I assume that decltype() would have to do some sort of recursion to be able to deduce the type of t + sum(p...). Is this legal C++0x? or does decltype() only work with non-variadic declarations? If that is the case, how would you write such a function?
I think the problem is that the variadic function template is only considered declared after you specified its return type so that sum in decltype can never refer to the variadic function template itself. But I'm not sure whether this is a GCC bug or C++0x simply doesn't allow this. My guess is that C++0x doesn't allow a "recursive" call in the ->decltype(expr) part.
As a workaround we can avoid this "recursive" call in ->decltype(expr) with a custom traits class:
#include <iostream>
#include <type_traits>
using namespace std;
template<class T> typename std::add_rvalue_reference<T>::type val();
template<class T> struct id{typedef T type;};
template<class T, class... P> struct sum_type;
template<class T> struct sum_type<T> : id<T> {};
template<class T, class U, class... P> struct sum_type<T,U,P...>
: sum_type< decltype( val<const T&>() + val<const U&>() ), P... > {};
This way, we can replace decltype in your program with typename sum_type<T,P...>::type and it will compile.
Edit: Since this actually returns decltype((a+b)+c) instead of decltype(a+(b+c)) which would be closer to how you use addition, you could replace the last specialization with this:
template<class T, class U, class... P> struct sum_type<T,U,P...>
: id<decltype(
val<T>()
+ val<typename sum_type<U,P...>::type>()
)>{};
Apparently you can't use decltype in a recursive manner (at least for the moment, maybe they'll fix it)
You can use a template structure to determine the type of the sum
It looks ugly but it works
#include <iostream>
using namespace std;
template<typename... T>
struct TypeOfSum;
template<typename T>
struct TypeOfSum<T> {
typedef T type;
};
template<typename T, typename... P>
struct TypeOfSum<T,P...> {
typedef decltype(T() + typename TypeOfSum<P...>::type()) type;
};
template <class T>
T sum(const T& in)
{
return in;
}
template <class T, class... P>
typename TypeOfSum<T,P...>::type sum(const T& t, const P&... p)
{
return t + sum(p...);
}
int main()
{
cout << sum(5, 10.0, 22.2) << endl;
}
C++14's solution:
template <class T, class... P>
decltype(auto) sum(const T& t, const P&... p){
return t + sum(p...);
}
Return type is deducted automatically.
See it in online compiler
Or even better if you want to support different types of references:
template <class T, class... P>
decltype(auto) sum(T &&t, P &&...p)
{
return std::forward<T>(t) + sum(std::forward<P>(p)...);
}
See it in online compiler
If you need a natural order of summation (that is (((a+b)+c)+d) instead of (a+(b+(c+d)))), then the solution is more complex:
template <class A>
decltype(auto) sum(A &&a)
{
return std::forward<A>(a);
}
template <class A, class B>
decltype(auto) sum(A &&a, B &&b)
{
return std::forward<A>(a) + std::forward<B>(b);
}
template <class A, class B, class... C>
decltype(auto) sum(A &&a, B &&b, C &&...c)
{
return sum( sum(std::forward<A>(a), std::forward<B>(b)), std::forward<C>(c)... );
}
See it in online compiler
Another answer to the last question with less typing by using C++11's std::common_type: Simply use
std::common_type<T, P ...>::type
as return type of your variadic sum.
Regarding std::common_type, here is an excerpt from http://en.cppreference.com/w/cpp/types/common_type:
For arithmetic types, the common type may also be viewed as the type
of the (possibly mixed-mode) arithmetic expression such as T0() + T1()
+ ... + Tn().
But obviously this works only for arithmetic expressions and doesn't cure the general problem.
I provide this improvement to the accepted answer. Just two structs
#include <utility>
template <typename P, typename... Ps>
struct sum_type {
using type = decltype(std::declval<P>() + std::declval<typename sum_type<Ps...>::type>());
};
template <typename P>
struct sum_type<P> {
using type = P;
};
Now just declare your functions as
template <class T>
auto sum(const T& in) -> T
{
return in;
}
template <class P, class ...Ps>
auto sum(const P& t, const Ps&... ps) -> typename sum_type<P, Ps...>::type
{
return t + sum(ps...);
}
With this, your test code now works
std::cout << sum(5, 10.0, 22.2, 33, 21.3, 55) << std::endl;
146.5
Right way to do:
#include <utility>
template <typename... Args>
struct sum_type;
template <typename... Args>
using sum_type_t = typename sum_type<Args...>::type;
template <typename A>
struct sum_type<A> {
using type = decltype( std::declval<A>() );
};
template <typename A, typename B>
struct sum_type<A, B> {
using type = decltype( std::declval<A>() + std::declval<B>() );
};
template <typename A, typename B, typename... Args>
struct sum_type<A, B, Args...> {
using type = sum_type_t< sum_type_t<A, B>, Args... >;
};
template <typename A>
sum_type_t<A> sum(A &&a)
{
return (std::forward<A>(a));
}
template <typename A, typename B>
sum_type_t<A, B> sum(A &&a, B &&b)
{
return (std::forward<A>(a) + std::forward<B>(b));
}
template <typename A, typename B, typename... C>
sum_type_t<A, B, C...> sum(A &&a, B &&b, C &&...args)
{
return sum( sum(std::forward<A>(a), std::forward<B>(b)), std::forward<C>(args)... );
}
https://coliru.stacked-crooked.com/a/a5a0e8019e40b8ba
This completely preserves resulting type of operations (even r-value referenceness). The order of operations is natural: (((a+b)+c)+d).
For C++17:
template <class... P>
auto sum(const P... p){
return (p + ...);
}
int main()
{
std::cout << sum(1, 3.5, 5) << std::endl;
return EXIT_SUCCESS;
}
Read about folding expressions.