How would i use enable_if to disable the constructor if the function passed into the template does not contain valid arguments.
template <typename SrcType>
using is_Valid_Ret_Type = std::bool_constant<
std::is_same<SrcType, void>::value |
std::is_same<SrcType, int>::value>;
template <typename SrcType>
using is_Valid_Arg_Type = std::bool_constant<
std::is_integral<SrcType>::value /*|
std::is_same<SrcType, float>::value*/>;
template<typename Fn> class FunctionBase;
template<typename R, typename... Args>
class FunctionBase <R(__cdecl*)(Args...)>
{
// ......
};
template <auto F>
class Function : public FunctionBase<decltype(F)> {
public:
template <typename R, typename... Args>
static R return_type_of(R(*)(Args...)) {};
template<
typename = std::enable_if_t<is_Valid_Ret_Type<decltype(return_type_of(F))>::value>,
typename = std::enable_if_t<(is_Valid_Arg_Type<Args>::value&& ...)>> // how do I do this
Function() : FunctionBase<decltype(F)>() { }
};
Partial specialization might help in your case, mostly the same way as for the Base class:
template <auto F>
class Function;
template <typename R, typename... Args, R (*F)(Args...)>
class Function<F> : public FunctionBase<decltype(F)> {
public:
static_assert(is_Valid_Ret_Type<R>::value);
static_assert((true && ... && is_Valid_Arg_Type<Args>::value));
Function() : FunctionBase<decltype(F)>() { }
};
Your SFINAE attempt also failed as condition has been fixed by the class, producing hard error instead of SFINAE.
You can use a helper function to check if all arguments are valid.
template <typename R, typename ... Args>
static auto are_args_valid(R(*)(Args...))
{
return std::bool_constant<(true && ... && is_Valid_Arg_Type<Args>::value)>{};
}
In the above helper function, I am using a fold expression to check if each and every argument type is valid.
This can then be used inside enable_if to check if all arguments are valid, like so
template<
typename = std::enable_if_t<is_Valid_Ret_Type<decltype(return_type_of(F))>::value>,
typename = std::enable_if_t<decltype(are_args_valid(F))::value>>
Function() : FunctionBase<decltype(F)>() { }
Here is a demo on golbolt.
Related
Let's consider a kind of "invoke" function (here named "call") that helps to call a member function passed by a template argument.
In this function, I would need to know the type of the class that owns the member function. Is there a way (in c++14 preferably) to do so ?
#include <functional>
template<typename F, typename... Args, std::enable_if_t<std::is_member_pointer<std::decay_t<F>>{}, int> = 0 >
constexpr decltype(auto) call(F&& f, Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
{
// Here we know that f is a member function, so it is of form : &some_class::some_function
// Is there a way here to infer the type some_class from f ? For exemple to instantiate a variable from it :
// imaginary c++ : class_of(f) var;
return std::mem_fn(f)(std::forward<Args>(args)...);
}
int main()
{
struct Foo { void bar() {} } foo;
call(&Foo::bar, &foo /*, args*/);
return 0;
}
template <typename>
struct class_of;
template <typename C, typename R, typename... Args>
struct class_of<R(C::*)(Args...)> {
using type = C;
};
Then you can get the type like typename class_of<F>::type. E.g.
template<typename F, typename... Args, std::enable_if_t<std::is_member_pointer<std::decay_t<F>>{}, int> = 0 >
constexpr decltype(auto) call(F&& f, Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
{
typename class_of<F>::type var;
return std::mem_fn(f)(std::forward<Args>(args)...);
}
BTW, It depends on your intent, but you can change the template paramters' declaration to get the class type directly.
// I remove the type check because only member function pointer could be passed in
template<typename C, typename R, typename... FArgs, typename... Args>
constexpr decltype(auto) call(R(C::*f)(FArgs...), Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
{
C var;
return std::mem_fn(f)(std::forward<Args>(args)...);
}
songyuanyao beat me to it, but note that you don't need to spell out the function type to deconstruct the member pointer:
template <class MemberPtr>
struct mptr_class;
template <class T, class Class>
struct mptr_class<T Class::*> {
using type = Class;
};
template <class MemberPtr>
using mptr_class_t = typename mptr_class<MemberPtr>::type;
I'm trying to implement compile-time configurable callback for sync/async call behaviour.
Here is the first approach to do that:
//emit type's
enum EEmitType
{
SYNC,
ASYNC,
};
//general
template<EEmitType et, typename... Args>
class callback_impl;
//implementation
template<EEmitType et, typename R, typename... Args>
class callback_impl<et, R(Args...)>
{ /*todo*/ };
//................................................................
//convert enum value to type or SFINAE
template <EEmitType et>
using callback_emit_type = std::integral_constant<EEmitType, et>;
//(for default SYNC)
template <typename T>
struct is_emit_type : std::false_type {};
//(for any other implementation)
template <EEmitType et>
struct is_emit_type<callback_emit_type<et>> : std::true_type {};
//................................................................
//metafunction
template <typename T>
using is_emit_type_t = typename is_emit_type<T>::type;
//................................................................
//for decl. like: callback<void()>
template <typename _unused, typename... Args>
struct construct_callback_impl
{
//alias on implementation
using type = callback_impl<SYNC, Args...>;
};
//for decl. like: callback<callback_emit_type<ASYNC>, void()>
template <typename EEmitType, typename... Args>
struct construct_callback_impl<typename
std::enable_if<is_emit_type_t<EEmitType>::value>::type, EEmitType, Args...>
{
//alias on implementation
using type = callback_impl<EEmitType::value, Args...>;
};
//................................................................
//user alias
template <typename... Args>
using callback = typename construct_callback_impl<Args...>::type;
Now USING:
callback<int(int)> ff_s; //<-- uses undefined class 'callback_impl<SYNC>'
callback<callback_emit_type<ASYNC>, int(int)> ff_a; //<--OK
Of course because first args is eating, and for success compilation it should be write down like:
callback<int(int), int(int)> ff_s
But of course it's not unacceptable.
OK, then I try extract EEmitType from Args...
//for decl. like: callback<void()>
template <typename... Args>
struct construct_callback_impl
{
//alias on implementation
using type = int; //temporary stub
};
//for decl. like: callback<callback_emit_type<ASYNC>, void()>
template <typename... Args>
struct construct_callback_impl<typename std::enable_if<is_emit_type_t< typename std::tuple_element_t<0, std::tuple<Args...> >::type >::value>::type, Args...>
{
//alias on implementation
using type = int; //temporary stub
};
BUT now I get the:
error C2338: tuple index out of bounds
note: see reference to class template instantiation 'std::tuple_element<0,std::tuple<>>' being compiled
Something like this should work
template <typename>
struct emit_type_value : std::integral_constant<EEmitType, SYNC> {};
template <EEmitType x>
struct emit_type_value<callback_emit_type<x>> : std::integral_constant<EEmitType, x> {};
//for decl. like: callback<void()>
template <typename Arg0, typename ... Args>
struct construct_callback_impl
{
//alias on implementation
using type = std::conditional_t<is_emit_type<Arg0>::value,
callback_impl<emit_type_value<Arg0>::value, Args...>,
callback_impl<SYNC, Arg0, Args...>>;
};
It would be somewhat terser if you just used false and true instead of SYNC and ASYNC.
I have the following code:
template <template <class...> class Temp, class Specialization>
struct IsSpecialization : std::false_type {};
template <template <typename...> class Temp1,
template <typename...> class Temp2, typename... Ts>
struct IsSpecialization<Temp1, Temp2<Ts...>>
: std::is_same<Temp1<Ts...>, Temp2<Ts...>> {};
struct ExprKindMerge {};
struct ExprKindSequence {};
template <class Tag, class... Args>
struct Expr {
std::tuple<Args...> tup;
constexpr std::tuple<Args...> toStdTuple() const {
return this->tup;
}
constexpr std::size_t size() const noexcept {
return std::tuple_size<decltype(tup)>{};
}
};
template <class...Args>
using MergeExpr = Expr<ExprKindMerge, Args...>;
template <class...Args>
using SequenceExpr = Expr<ExprKindSequence, Args...>;
And this function, which sometimes receives a SequenceExpr<Something> as the template parameter:
template <class FullExpr>
auto f(FullExpr expr) {
///**************THIS RETURNS FALSE I EXPECT TRUE
///Type of full expr is Expr<ExprKindSequence, ...> which is
/// the expansion of SequenceExpr<...>
if constexpr (IsSpecialization<SequenceExpr, FullExpr>::value)
//...
}
I want to be able to detect if FullExpr is a specialization of SequenceExpr but it fails for some unknown reason.
Why it fails is easy. For a SequenceExpr<ExtraArgs...>, Temp2 is deduced to be Expr and Ts... is deduced to be ExprKindSequence, ExtraArgs.... Then Temp1<Ts...> is Expr<ExprKindSequence, ExprKindSequence, ExtraArgs...> and is obviously not the same as Temp2<Ts...>.
I know of no fully generic way to do this. After all, such a hypothetical template would presumably need to return true for IsSpecialization<std::remove_reference_t, int>...
If we limit it to alias templates that use their parameters in deducible contexts (which is the case in your example), then one possible way is to ask the question "Can I deduce the Ts... in Temp<Ts...> from Specialization?":
namespace detail {
template<class> class type {};
template<template<class...> class Temp, class...Ts>
void try_deduce(type<Temp<Ts...>>);
}
template <template <class...> class, class, class = void>
struct IsSpecialization : std::false_type {};
template <template <typename...> class Temp, class Specialization>
struct IsSpecialization<Temp, Specialization,
decltype(detail::try_deduce<Temp>(detail::type<Specialization>()))>
: std::true_type {};
static_assert(IsSpecialization<SequenceExpr, SequenceExpr<int>>()());
static_assert(IsSpecialization<Expr, SequenceExpr<int>>()());
static_assert(!IsSpecialization<MergeExpr, SequenceExpr<int>>()());
static_assert(!IsSpecialization<SequenceExpr, MergeExpr<int>>()());
If your interested only in detecting specializations of SequenceExpr, the best I can imagine is to add a specialization of IsSpecialization defined as follows
template <typename... Ts>
struct IsSpecialization<SequenceExpr, Expr<ExprKindSequence, Ts...>>
: std::true_type
{ };
Obviously this isn't a general solution that I don't think it's possible.
Take in count that if you call f with a (by example) Expr<ExprKindSequence, int, long> value
f(Expr<ExprKindSequence, int, long>{}); // result true !!!
the specialization of IsSpecialization above match and you get true; I don't know if is what do you want.
The following is a full working example
#include <tuple>
#include <iostream>
#include <type_traits>
template <template <typename...> typename Temp, typename Specialization>
struct IsSpecialization : std::false_type
{ };
template <template <typename...> class Temp1,
template <typename...> class Temp2, typename... Ts>
struct IsSpecialization<Temp1, Temp2<Ts...>>
: std::is_same<Temp1<Ts...>, Temp2<Ts...>>
{ };
struct ExprKindMerge {};
struct ExprKindSequence {};
template <typename Tag, typename... Args>
struct Expr
{
std::tuple<Args...> tup;
constexpr std::tuple<Args...> toStdTuple () const
{ return this->tup; }
constexpr std::size_t size () const noexcept
{ return std::tuple_size<decltype(tup)>{}; }
};
template <typename ... Args>
using MergeExpr = Expr<ExprKindMerge, Args...>;
template <typename ... Args>
using SequenceExpr = Expr<ExprKindSequence, Args...>;
template <typename ... Ts>
struct IsSpecialization<SequenceExpr, Expr<ExprKindSequence, Ts...>>
: std::true_type
{ };
template <class FE>
auto f (FE expr)
{ std::cout << IsSpecialization<SequenceExpr, FE>::value << std::endl; }
int main ()
{
f(SequenceExpr<int, long>{}); // print 1
f(Expr<ExprKindSequence, int, long>{}); // print 1 (?)
f(Expr<int, long>{}); // print 0
f(int{}); // print 0
}
I have a class, Delegate, declared like this:
template<typename T> class Delegate;
template<typename R, typename... Args>
class Delegate<R(Args...)>
{ /*...*/ };
It can be instantiated for a function returning a ReturnType and taking no arguments as a Delegate<ReturnType()>. I've run into an issue that requires me to specialize the class' () operator for this case, but haven't been able to figure out how to coerce the compiler doing so without a compiler error.
I have the following function:
template <typename R, typename... Args>
R Delegate<R(Args...)>::operator()(Args... args)
{ /*...*/ }
Adding the following specialization, I get an an error saying invalid use of incomplete type 'class Delegate<R()>':
template <typename R>
R Delegate<R()>::operator()()
{ /*...*/ }
but I can't simply replace Args... with void either, as far as I've been able to tell... What is the proper procedure here, and (if this question applies and you are feeling extra helpful) why?
Your attempt with using R Delegate<R()>::operator()() to specialize even more the member function of a partial specialization of a class template fails due to ยง14.5.5.3 [temp.class.spec.mfunc]:
1 The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization.
In other words:
template <typename R>
R Delegate<R()>::operator()() { /**/ }
is actually a specialization of operator() of your primary template:
template <typename T>
class Delegate;
and since it's an incomplete type, you end up with the error. The possible workarounds are:
Option #1
Specialize the entire class and reimplement all the members of that class:
template <typename T>
class Delegate;
template <typename R, typename... Args> // partial specialization for non-empty Args
class Delegate<R(Args...)>
{
R operator()(Args...) { return {}; }
};
template <typename R> // partial specialization for empty Args
class Delegate<R()>
{
R operator()() { return {}; }
};
DEMO 1
Option #2
Use a one more delegate class that is specialized:
#include <utility>
template <typename T>
struct Impl;
template <typename R, typename... Args>
struct Impl<R(Args...)>
{
static R call(Args&&...) { return {}; }
};
template <typename R>
struct Impl<R()>
{
static R call() { return {}; }
};
template <typename T>
class Delegate;
template <typename R, typename... Args>
class Delegate<R(Args...)>
{
R operator()(Args... args)
{
return Impl<R(Args...)>::call(std::forward<Args>(args)...);
}
};
DEMO 2
Option #3
Use some ugly SFINAE:
#include <type_traits>
template <typename T>
class Delegate;
template <typename R, typename... Args>
class Delegate<R(Args...)>
{
template <typename T = R>
typename std::enable_if<sizeof...(Args) != 0 && std::is_same<T,R>{}, R>::type
operator()(Args...) { return {}; }
template <typename T = R>
typename std::enable_if<sizeof...(Args) == 0 && std::is_same<T,R>{}, R>::type
operator()() { return {}; }
};
DEMO 3
Option #4
Inherit from a specialized class template, possibly utilizing the CRTP idiom:
template <typename T>
class Delegate;
template <typename T>
struct Base;
template <typename R, typename... Args>
struct Base<Delegate<R(Args...)>>
{
R operator()(Args...)
{
Delegate<R(Args...)>* that = static_cast<Delegate<R(Args...)>*>(this);
return {};
}
};
template <typename R>
struct Base<Delegate<R()>>
{
R operator()()
{
Delegate<R()>* that = static_cast<Delegate<R()>*>(this);
return {};
}
};
template <typename R, typename... Args>
class Delegate<R(Args...)> : public Base<Delegate<R(Args...)>>
{
friend struct Base<Delegate<R(Args...)>>;
};
DEMO 4
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.