Say I have 5 classes, A-E.
I want to create a class Gadget that can be constructed from 0-5 parameters which are constrained to be a const reference to types A,B,C,D, or E in any order and without duplicates.
What is the cleanest way to implement this?
The following solves your problem:
#include <type_traits>
#include <tuple>
// find the index of a type in a list of types,
// return sizeof...(Ts) if T is not found
template< typename T, typename... Ts >
struct index_by_type : std::integral_constant< std::size_t, 0 > {};
template< typename T, typename... Ts >
struct index_by_type< T, T, Ts... > : std::integral_constant< std::size_t, 0 >
{
static_assert( index_by_type< T, Ts... >::value == sizeof...( Ts ), "duplicate type detected" );
};
template< typename T, typename U, typename... Ts >
struct index_by_type< T, U, Ts... > : std::integral_constant< std::size_t, index_by_type< T, Ts... >::value + 1 > {};
// get the element from either "us" if possible...
template< std::size_t I, std::size_t J, typename T, typename... Us, typename... Ts >
auto get_by_index( const std::tuple< Us... >&, const std::tuple< Ts... >& ts )
-> typename std::enable_if< I == sizeof...( Us ), const T& >::type
{
return std::get< J >( ts );
}
// ...get the element from "ts" otherwise
template< std::size_t I, std::size_t J, typename T, typename... Us, typename... Ts >
auto get_by_index( const std::tuple< Us... >& us, const std::tuple< Ts... >& )
-> typename std::enable_if< I != sizeof...( Us ), const T& >::type
{
return std::get< I >( us );
}
// helper to validate that all Us are in Ts...
template< bool > struct invalide_type;
template<> struct invalide_type< true > : std::true_type {};
template< std::size_t... > void validate_types() {}
template< typename T >
struct dflt
{
static const T value;
};
template< typename T >
const T dflt< T >::value;
// reorder parameters
template< typename... Ts, typename... Us >
std::tuple< const Ts&... > ordered_tie( const Us&... us )
{
auto t1 = std::tie( us... );
auto t2 = std::tie( dflt< Ts >::value... );
validate_types< invalide_type< index_by_type< const Us&, const Ts&... >::value != sizeof...( Ts ) >::value... >();
return std::tie( get_by_index< index_by_type< const Ts&, const Us&... >::value,
index_by_type< const Ts&, const Ts&... >::value, Ts >( t1, t2 )... );
}
struct A {};
struct B {};
struct C {};
struct Gadget
{
A a;
B b;
C c;
explicit Gadget( const std::tuple< const A&, const B&, const C& >& t )
: a( std::get<0>(t) ),
b( std::get<1>(t) ),
c( std::get<2>(t) )
{}
template< typename... Ts >
Gadget( const Ts&... ts ) : Gadget( ordered_tie< A, B, C >( ts... ) ) {}
};
int main()
{
A a;
B b;
C c;
Gadget g1( a, b, c );
Gadget g2( b, c, a );
Gadget g3( a, b ); // uses a default-constructed C
Gadget g4( a, c ); // uses a default-constructed B
Gadget g5( c ); // uses a default-constructed A and B
Gadget g6; // uses a default-constructed A, B and C
// fails to compile:
// Gadget gf1( a, a ); // duplicate type
// Gadget gf2( a, b, 42 ); // invalid type
}
Live example
Easy just use variadic templates and a static_assert
template <typename ... Types>
struct thing
{
static_assert(sizeof...(Types) <= 5,"Too many objects passed");
};
int main()
{
thing<int,float,double,int,int> a;
return 0;
}
Preventing duplicates might be tricky, I still have to think of that one.
Honestly I can't think of any un-painful way to ensure that all the types are different but the solution will likely involve std::is_same one definite way to make it work would be to have specializations for 0 - 5 types and use a static_assert to check all the combinations in each specialization, this will definitely be a pain though.
EDIT: well this was fun
template <typename ... Types>
struct thing
{
static_assert(sizeof ... (Types) <= 5,"Too big");
};
template <>
struct thing<> {};
template <typename A>
struct thing<A>{};
template <typename A, typename B>
struct thing<A,B>
{
static_assert(!std::is_same<A,B>::value,"Bad");
};
template <typename A, typename B, typename C>
struct thing<A,B,C>
{
static_assert(!std::is_same<A,B>::value &&
!std::is_same<A,C>::value &&
!std::is_same<C,B>::value,"Bad");
};
template <typename A, typename B, typename C, typename D>
struct thing<A,B,C,D>
{
static_assert(!std::is_same<A,B>::value &&
!std::is_same<A,C>::value &&
!std::is_same<C,B>::value &&
!std::is_same<C,D>::value &&
!std::is_same<B,D>::value &&
!std::is_same<A,D>::value,"Bad");
};
template <typename A, typename B, typename C, typename D, typename E>
struct thing<A,B,C,D,E>
{
static_assert(!std::is_same<A,B>::value &&
!std::is_same<A,C>::value &&
!std::is_same<C,B>::value &&
!std::is_same<C,D>::value &&
!std::is_same<B,D>::value &&
!std::is_same<A,D>::value &&
!std::is_same<A,E>::value &&
!std::is_same<B,E>::value &&
!std::is_same<C,E>::value &&
!std::is_same<D,E>::value,"Bad");
};
int main()
{
thing<> a;
thing<int,float,int> b; //error
thing<int,float,double,size_t,char> c;
thing<int,float,double,size_t,char,long> d; //error
return 0;
}
To create a more general approach what you have to do is create a compile time combination meta function
The question asks for a Gaget class that can be constructed with [0-5] number of parameters constrained to 5 different types without duplication, and with any order. With the help of templates it's doable; below is an example for two parameters, and it's easily extensible to 5 parameters.
class A
{
};
class B
{
};
template<typename T> struct is_A
{
enum { value = false };
};
template<> struct is_A<A>
{
enum { value = true };
};
template<typename T> struct is_B
{
enum { value = false };
};
template<> struct is_B<B>
{
enum { value = true };
};
template <bool V> struct bool_to_count
{
enum {value = V ? 1 : 0};
};
class Gaget
{
public:
template <typename T1> Gaget(const T1& t1)
{
static_assert(is_A<T1>::value || is_B<T1>::value, "T1 can only be A or B");
if (is_A<T1>::value)
{
m_a = *reinterpret_cast<const A*>(&t1);
}
if (is_B<T1>::value)
{
m_b = *reinterpret_cast<const B*>(&t1);
}
}
template <typename T1, typename T2> Gaget(const T1& t1, const T2& t2)
{
static_assert(is_A<T1>::value || is_B<T1>::value, "T1 can only be A or B");
static_assert(is_A<T2>::value || is_B<T2>::value, "T2 can only be A or B");
const int countA = bool_to_count<is_A<T1>::value>::value
+ bool_to_count<is_A<T2>::value>::value;
static_assert(countA == 1, "One and only one A is allowed");
const int countB = bool_to_count<is_B<T1>::value>::value
+ bool_to_count<is_B<T2>::value>::value;
static_assert(countA == 1, "One and only one B is allowed");
if(is_A<T1>::value)
{
// it's safe because it's only executed when T1 is A;
// same with all following
m_a = *reinterpret_cast<const A*>(&t1);
}
if(is_B<T1>::value)
{
m_b = *reinterpret_cast<const B*>(&t1);
}
if (is_A<T2>::value)
{
m_a = *reinterpret_cast<const A*>(&t2);
}
if (is_B<T2>::value)
{
m_b = *reinterpret_cast<const B*>(&t2);
}
}
private:
A m_a;
B m_b;
};
void foo(const A& a, const B& b)
{
auto x1 = Gaget(b,a);
auto x2 = Gaget(a,b);
auto x3 = Gaget(a);
auto x4 = Gaget(b);
// auto x5 = Gaget(a,a); // error
// auto x6 = Gaget(b,b); // error
}
If you are willing to make compromises on the syntax, you can do it with the Builder pattern. The usage would look like this:
Gadget g = Gadget::builder(c)(a)(b)();
Yes, this syntax is not very nice and perhaps a bit obscure but it is a reasonable compromise. The good news is that you avoid the combinatorial explosion: This solutions scales linearly with the number of arguments. One downside is that duplicate arguments are detected only at runtime.
Sample code for 3 types (may contain errors):
#include <iostream>
#include <stdexcept>
struct A { char value = ' '; };
struct B { char value = ' '; };
struct C { char value = ' '; };
struct state { A a; B b; C c; };
class Gadget {
private:
Gadget(state s) : s(s) { };
state s;
public:
class builder {
public:
template <class T>
builder(T t) { reference(t) = t; }
template <class T>
builder& operator()(T t) { return assign(reference(t), t); }
Gadget operator()() { return Gadget(s); }
private:
template <class T>
builder& assign(T& self, T t) {
if (self.value != ' ')
throw std::logic_error("members can be initialized only once");
self = t;
return *this;
}
A& reference(A ) { return s.a; }
B& reference(B ) { return s.b; }
C& reference(C ) { return s.c; }
state s;
};
friend std::ostream& operator<<(std::ostream& out, const Gadget& g) {
out << "A: " << g.s.a.value << std::endl;
out << "B: " << g.s.b.value << std::endl;
return out << "C: " << g.s.c.value << std::endl;
}
};
int main() {
A a; a.value = 'a';
B b; b.value = 'b';
C c; c.value = 'c';
Gadget g = Gadget::builder(c)(a)(b)();
std::cout << "Gadget:\n" << g << std::endl;
}
Far from perfect but I personally find it easier to read and understand than the solutions using template metaprogramming.
Here is a working solution, still not sure of the optimal solution.
#include <iostream>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/insert.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/has_key.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/for_each.hpp>
struct A{
A() { std::cout << "A default constructor" << std::endl; }
~A() { std::cout << "A destructor" << std::endl; }
A( const A& ) { std::cout << "A copy constructor" << std::endl; }
A( A&& ) { std::cout << "A move constructor" << std::endl; }
};
struct B{
B() { std::cout << "B default constructor" << std::endl; }
~B() { std::cout << "B destructor" << std::endl; }
B( const B& ) { std::cout << "B copy constructor" << std::endl; }
B( B&& ) { std::cout << "B move constructor" << std::endl; }
};
struct C{
C() { std::cout << "C default constructor" << std::endl; }
~C() { std::cout << "C destructor" << std::endl; }
C( const C& ) { std::cout << "C copy constructor" << std::endl; }
C( C&& ) { std::cout << "C move constructor" << std::endl; }
};
struct D{
D() { std::cout << "D default constructor" << std::endl; }
~D() { std::cout << "D destructor" << std::endl; }
D( const D& ) { std::cout << "D copy constructor" << std::endl; }
D( D&& ) { std::cout << "D move constructor" << std::endl; }
};
struct E{
E() { std::cout << "E default constructor" << std::endl; }
~E() { std::cout << "E destructor" << std::endl; }
E( const E& ) { std::cout << "E copy constructor" << std::endl; }
E( E&& ) { std::cout << "E move constructor" << std::endl; }
};
class Gadget
{
struct call_setters
{
Gadget& self;
call_setters( Gadget& self_ ) : self( self_ ){}
template< typename T >
void operator()( T& t ) const
{
self.set( t );
}
};
public:
template< typename... Args >
Gadget( const Args&... args )
{
using namespace boost::mpl;
using namespace boost::mpl::placeholders;
typedef vector<A, B, C, D, E> allowed_args;
static_assert(sizeof...(Args) <= size<allowed_args>::value, "Too many arguments");
typedef typename fold< vector<Args...>
, set0<>
, insert<_1, _2>
>::type unique_args;
static_assert(size<unique_args>::value == sizeof...(Args), "Duplicate argument types");
typedef typename fold< allowed_args
, int_<0>
, if_< has_key<unique_args, _2 >, next<_1>, _1 >
>::type allowed_arg_count;
static_assert(allowed_arg_count::value == sizeof...(Args), "One or more argument types are not allowed");
namespace bf = boost::fusion;
bf::for_each( bf::vector<const Args&...>( args... ), call_setters{ *this } );
}
void set( const A& ) { std::cout << "Set A" << std::endl; }
void set( const B& ) { std::cout << "Set B" << std::endl; }
void set( const C& ) { std::cout << "Set C" << std::endl; }
void set( const D& ) { std::cout << "Set D" << std::endl; }
void set( const E& ) { std::cout << "Set E" << std::endl; }
};
int main()
{
Gadget{ A{}, E{}, C{}, D{}, B{} };
}
Live Demo
Related
callable should be any function pointer, std::function or lambda. I want to obtain their argument list and use them as parameter pack:
template <typename callable_T>
class callback2_t
{
public:
using callable_t = callable_T;
using ret_T = some_magic<callable_T>::ret_t;
using data_T = the_first_type<argTs>;
...
static ret_T _callback(some_magic<callable_T>::argTs... args);
};
The purpose is to simplify follow templates to make it work for all kind of callable without creating alias:
// other library only accept function pointer as callback, I want to wrap it to remove the callback when data go out of scope.
template <typename callable_T, typename ret_T, typename data_T, typename ...arg_Ts>
class callback_t
{
using callable_t = callable_T;
public:
callback_t(const char* signal, callable_t callable, data_T data)
: f_{std::move(callable)}, data_{std::move(data)}
{
std::cout << signal << " " << typeid(callable).name() << std::endl;
//register_callback(signal, _callback, this);
}
~callback_t()
{
//unregister_callback(signal);
}
void test_callback(arg_Ts... args)
{
_callback(args..., this);
}
private:
callable_t f_;
data_T data_;
static ret_T _callback(arg_Ts... args, callback_t * self)
{
return self->f_(&self->data_, args...);
}
};
// I donot want convert function pointer to std::function
// if possible. std::function is a heavy class.
template <typename ret_T, typename data_T, typename ...arg_Ts>
using fp_callback_t = callback_t<ret_T(*)(void *, arg_Ts...), ret_T, data_T, arg_Ts...>;
template <typename ret_T, typename data_T, typename ...arg_Ts>
using func_callback_t = callback_t<std::function<ret_T(void *, arg_Ts...)>, ret_T, data_T, arg_Ts...>;
We can use the template like this:
struct A{float x;};
struct B{int x;};
struct C{uint x;};
int func1(void * data, A* a)
{
auto c = reinterpret_cast<C*>(data);
std::cout<< a->x << ", " << c->x << std::endl;
return a->x + c->x;
}
void func2(void *data, B* b, C* c)
{
auto a = reinterpret_cast<A*>(data);
std::cout << b->x << ", " << c->x << ", " << a->x << std::endl;
}
int main()
{
A a1{-10.5f};
B b1 {5};
C c1{300};
auto callback1 = fp_callback_t<int, C, A*>("signal1", &func1, c1);
callback1.test_callback(&a1);
auto callback2 = fp_callback_t<void, A, B*, C*>("signal2", &func2, a1);
callback2.test_callback(&b1, &c1);
std::function<int(void*, A*)> fc1 = [=](void* data, A* a){
auto c = reinterpret_cast<C*>(data);
std::cout<< a->x << ", " << c->x << ", " << a1.x << std::endl;
return (int)a1.x;
};
std::function<void(void*, B*, C*)> fc2 = [=](void* data, B* b, C* c){
auto a = reinterpret_cast<A*>(data);
std::cout << b->x << ", " << c->x << ", " << a->x << ", " << c1.x << std::endl;
};
auto callback3 = func_callback_t<int, C, A*>("signal3", fc1, c1);
callback3.test_callback(&a1);
auto callback4 = func_callback_t<void, A, B*, C*>("signal4", fc2, a1);
callback4.test_callback(&b1, &c1);
return 0;
}
The out put is:
signal1 PFiPvP1AE
-10.5, 300
signal2 PFvPvP1BP1CE
5, 300, -10.5
signal3 NSt3__18functionIFiPvP1AEEE
-10.5, 300, -10.5
signal4 NSt3__18functionIFvPvP1BP1CEEE
5, 300, -10.5, 300
The deduction should work without specialize template parameters explicitly; I want to avoid alias; It should work with function pointer, std::function and lambda; the callable_t should be as it is given instead of casting all of them to std::function. like following:
auto callback1 = callback2_t("signal1", &func1, c1);
callback1.test_callback(&a1);
auto callback2 = callback2_t("signal2", &func2, a1);
callback2.test_callback(&b1, &c1);
std::function<int(void*, A*)> fc1 = [=](void* data, A* a){
auto c = reinterpret_cast<C*>(data);
std::cout<< a->x << ", " << c->x << ", " << a1.x << std::endl;
return (int)a1.x;
};
auto callback3 = callback2_t("signal3", fc1, c1);
callback3.test_callback(&a1);
auto lambda1 = [=](void* data, B* b, C* c){
auto a = reinterpret_cast<A*>(data);
std::cout << b->x << ", " << c->x << ", " << a->x << ", " << c1.x << std::endl;
};
auto callback4 = callback2_t("signal4", lambda1, a1);
callback4.test_callback(&b1, &c1);
You don't need to deduce the parameters at all. Just let the template soak them up and forward them to the callable.
template <typename callable_T, typename data_T>
class callback_t
{
using callable_t = callable_T;
public:
callback_t(const char* signal, callable_t callable, data_T data)
: f_{std::move(callable)}, data_{std::move(data)}
{
}
template<typename...arg_Ts>
auto test_callback(arg_Ts... args)
{
return _callback(this, args...);
}
private:
callable_t f_;
data_T data_;
template<typename...arg_Ts>
static auto _callback(callback_t * self, arg_Ts... args)
{
return self->f_(&self->data_, args...);
}
};
Works great even if operator() is overloaded:
int test()
{
callback_t cc("test", [](auto x, auto y){ return *x + y;}, 42);
return cc.test_callback(9); // returns 42 + 9 = 51
}
That was an interesting quiz =) The trick was to pass pointer to lambda::operator() and let type deduction work:
template <typename Ret, typename ... Args>
struct Callback {
Callback() {
std::cout << "Created " << typeid(*this).name() << "\n";
}
};
template <typename Ret, typename ... Args>
Callback<Ret, Args...> create_callback(std::function<Ret (Args...)> const &fn) {
std::cout << "Function!\n";
return Callback<Ret, Args...>();
}
template <typename Ret, typename ... Args>
Callback<Ret, Args...> create_callback(Ret (*fn)(Args...)) {
std::cout << "Function pointer!\n";
return Callback<Ret, Args...>();
}
template <typename Lambda, typename Ret, typename ... Args>
Callback<Ret, Args...> create_callback_lambda(Lambda const &, Ret (Lambda::*)(Args...) const) {
std::cout << "Lambda!\n";
return Callback<Ret, Args...>();
}
template <typename Callable>
auto create_callback(Callable const &c) {
return create_callback_lambda(c, &Callable::operator());
}
I am searching for something like swifts ? operator in c++ for std::function. I have grown to like it over the last couple years.
I would like a std::optional_function, which only calls the function if the function exists.
Something like this (but written by the gods of c++):
template<typename R>
struct option_function_result {
bool executed;
R result;
} ;
template<>
struct option_function_result<void>
{
bool executed;
} ;
template<typename F>
class optional_function
{
public:
typedef std::function<F> function_type;
typedef option_function_result<typename function_type::result_type> result_type;
protected:
function_type f;
public:
template<typename Fn>
optional_function operator=(const Fn &f_)
{
f = f_;
return *this;
}
template<typename Fn>
optional_function operator=(Fn &&f_)
{
f = std::forward<Fn>(f_);
return *this;
}
operator bool() const
{
return (bool)f;
}
template<typename ...Args, typename R>
result_type operator()(Args... args)
{
if (f)
return result_type { true, f(args...) };
return result_type { false };
}
template<typename ...Args>
result_type operator()(Args... args)
{
if (f)
{
f(args...);
return result_type { true };
}
return result_type { false };
}
} ;
Another revision
Here is revision 2. In order not to polute the question, and since I don't know if this will be a final answer, I'm gonna place it here for now:
I expect that the constructor for the struct is not necessary. However it forces the compiler to give me errors I need to debug the compilation.
template<typename R>
struct optional_function_result {
bool executed;
R result;
optional_function_result(bool &&executed_, R &&result_) :
executed (executed_),
result(result_) {}
} ;
template<>
struct optional_function_result<void>
{
bool executed;
optional_function_result(bool &&executed_) :
executed (executed_) {}
} ;
template<typename F>
class optional_function
{
public:
typedef std::function<F> function_type;
typedef typename std::function<F>::result_type function_result_type;
typedef optional_function_result<typename function_type::result_type> result_type;
protected:
function_type f;
public:
template<typename Fn>
optional_function operator=(const Fn &f_)
{
f = f_;
return *this;
}
template<typename Fn>
optional_function operator=(Fn &&f_)
{
f = std::forward<Fn>(f_);
return *this;
}
operator bool() const
{
return (bool)f;
}
template<
typename ... Args,
typename FR=function_result_type,
typename std::enable_if<!std::is_void<FR>::value, FR>::type* = nullptr
>
result_type operator()(Args... args) const
{
if (f)
return {
true,
std::forward<typename function_type::result_type>(f(args...))
};
return {
false,
function_result_type()
};
}
template<
typename ... Args,
typename FR=function_result_type,
typename std::enable_if<std::is_void<FR>::value, FR>::type* = nullptr
>
result_type operator()(Args... args) const
{
if (f)
{
f(args...);
return { true };
}
return { false };
}
} ;
Ok one more version, which uses basically optional to get rid of some edge cases.
template<typename T>
using optional_type = std::experimental::optional<T>;
template<typename R>
struct optional_function_result : optional_type<R> {
typedef optional_type<R> super_type;
optional_function_result() :
super_type() {}
optional_function_result(R &&result_) :
super_type(result_) {}
bool executed() const { return this->has_result(); }
} ;
template<>
struct optional_function_result<void>
{
bool executed_;
optional_function_result(bool &&executed__) :
executed_ (executed__) {}
bool executed() const { return executed_; }
} ;
template<typename F>
class optional_function
{
public:
typedef std::function<F> function_type;
typedef typename std::function<F>::result_type function_result_type;
typedef optional_function_result<typename function_type::result_type> result_type;
protected:
function_type f;
public:
template<typename Fn>
optional_function operator=(const Fn &f_)
{
f = f_;
return *this;
}
template<typename Fn>
optional_function operator=(Fn &&f_)
{
f = std::forward<Fn>(f_);
return *this;
}
operator bool() const
{
return (bool)f;
}
template<
typename ... Args,
typename FR=function_result_type,
typename std::enable_if<!std::is_void<FR>::value, FR>::type* = nullptr
>
result_type operator()(Args... args) const
{
if (f)
return {
std::forward<typename function_type::result_type>(f(args...))
};
return {};
}
template<
typename ... Args,
typename FR=function_result_type,
typename std::enable_if<std::is_void<FR>::value, FR>::type* = nullptr
>
result_type operator()(Args... args) const
{
if (f)
{
f(args...);
return { true };
}
return { false };
}
} ;
The ? operator works really well in C++ too:
// let function be of type std::function or a function pointer
auto var = f ? f() : default_value;
If you really want a type that does that, there is no such thing in the standard library, but a simple function is enough to do what you want (works only for function that don't return references or void):
template<typename F, typename... Args, typename R = std::invoke_result_t<F, Args&&...>>
auto optionally_call(F&& f, Args&&... args) -> std::optional<R> {
return f ? R(std::forward<F>(f)(std::forward<Args>(args)...)) : std::nullopt;
}
With some metaprogramming, it's possible to support cases not supported by this implementation.
This is to highlight that there's a lot of pitfalls when creating a whole type that is meant to be generic. There are many mistakes and performance issues and even code that will cannot be called in your sample code. A simple utility function would be easier than a type.
The standard library doesn't have anything like that, but you can build one yourself:
#include <functional>
#include <iostream>
#include <optional>
template <typename T>
class optional_function {
private:
std::optional<T> func;
public:
optional_function(T f) : func{std::move(f)} {}
optional_function() = default;
template <typename... Args>
auto operator()(Args&&... args) const {
using func_invoke_type = decltype((*func)(std::forward<Args>(args)...));
constexpr bool func_invoke_type_is_void = std::is_same_v<void, func_invoke_type>;
using optional_result_type = std::optional<
std::conditional_t<
func_invoke_type_is_void, // Can't have a std::optional<void>
char,
std::conditional_t<
std::is_reference_v<func_invoke_type>, // Can't have a std::optional<T&>
std::reference_wrapper<std::remove_reference_t<func_invoke_type>>,
func_invoke_type
>
>
>;
if (func) {
if constexpr (!func_invoke_type_is_void) {
return optional_result_type{(*func)(std::forward<Args>(args)...)};
} else {
(*func)(std::forward<Args>(args)...);
return optional_result_type{ '\0' }; // can't return void{} '
}
}
return optional_result_type{};
}
};
// Test it
void foo() {}
int main() {
optional_function f1{[](int i) { return i * i; }};
optional_function f2{[] { std::cout << "Hello World\n"; }};
decltype(f1) f3{};
optional_function f4{[](int a, const int& b) -> int const& {
std::cout << a + b << '\n';
return b;
}};
optional_function f5{foo};
auto res1 = f1(9);
auto res2 = f2();
auto res3 = f3(9);
int b = 5;
auto res4 = f4(1, b);
auto res5 = f5();
std::cout << std::boolalpha;
std::cout << "f1 is executed: " << res1.has_value() << ". result: " << *res1
<< '\n';
std::cout << "f2 is executed: " << res2.has_value() << '\n';
std::cout << "f3 is executed: " << res3.has_value() << '\n';
std::cout << "f4 is executed: " << res4.has_value() << ". result: " << *res4
<< '\n';
std::cout << "f5 is executed: " << res5.has_value() << '\n';
}
No, there is currently no such thing in the C++ Standard Library.
I want to enable/disable branches at compile time depending of whether a function can be called with certain arguments.
What has to go in the if constexpr condition?
I can get the result type via std::result_of(decltype(add)(A, B)), but how can I check, whether the result type is valid? (i.e. how to I convert this information to a bool?)
const auto add = [](const auto a, const auto b) { return a + b; };
const auto subtract = [](const auto a, const auto b) { return a - b; };
template <typename A, typename B>
void foo(A a, B b) {
if constexpr ( /* can add(a, b) be called? */ ) {
std::cout << "result of add: " << add(a, b) << std::endl;
}
if constexpr ( /* can subtract(a, b) be called? */ ) {
std::cout << "result of subtract: " << subtract(a, b) << std::endl;
}
}
First you need to make your lambdas SFINAE-friendly.
#define RETURNS(...)\
noexcept(noexcept(__VA_ARGS__))\
->decltype(__VA_ARGS__)\
{ return __VA_ARGS__; }
const auto add = [](const auto a, const auto b) RETURNS( a + b );
const auto subtract = [](const auto a, const auto b) RETURNS( a - b );
Now add and subract can be tested in a SFINAE context.
namespace details {
template<class, class, class...>
struct can_invoke:std::false_type {};
template<class F, class...Args>
struct can_invoke<F, std::void_t< std::result_of_t< F&&(Args&&...) > >, Args... >:
std::true_type
{};
}
template<class F, class...Args>
using can_invoke_t = details::can_invoke<F, Args...>;
template<class F, class...Args>
constexpr can_invoke_t< F, Args... >
can_invoke( F&&, Args&&... ){ return {}; }
and we are ready:
template <typename A, typename B>
void foo(A a, B b) {
if constexpr ( can_invoke( add, a, b ) ) {
std::cout << "result of add: " << add(a, b) << std::endl;
}
if constexpr ( can_invoke( subtract, a, b ) {
std::cout << "result of subtract: " << subtract(a, b) << std::endl;
}
}
this is c++14; in c++11 it is more awkward, in c++17 more elegant as they already have a can invoke type trait (which handles a few more corner cases; however, it also expects you to call add with std::invoke).
In c++17 I sort of like this trick:
template<class F>
constexpr auto invoke_test( F&& ) {
return [](auto&&...args) ->
can_invoke_t<F, decltype(args)...>
{ return {}; };
}
template <typename A, typename B>
void foo(A a, B b) {
if constexpr ( invoke_test( add )( a, b ) ) {
std::cout << "result of add: " << add(a, b) << std::endl;
}
if constexpr ( invoke_test( subtract )( a, b ) {
std::cout << "result of subtract: " << subtract(a, b) << std::endl;
}
}
where invoke_test takes a callable, and returns a callable whose only job is to answer "the original callable be invoked with the args you passed me".
You can put SFINAE to the return type and let function overloading tell whether a call can be made. A helper function can_be_called can be implemented as following:
#include <type_traits>
template<class Func, class... Args>
constexpr auto
can_be_called(Func&& func, Args&&... args)
-> decltype(
(std::forward<Func>(func)(std::forward<Args>(args)...)
, bool{}))
{ return true; }
struct Dummy {
template<class T> constexpr Dummy(T&&) {}
};
template<class... Args>
constexpr bool
can_be_called(Dummy, Args&&...) { return false; }
// test
#include <iostream>
void foo(int, int) {}
struct A{};
int main() {
if constexpr( can_be_called(foo, 1, 2) ) {
std::cout << "OK\n";
}
if constexpr ( !can_be_called(foo, A{}, 2) ) {
std::cout << "NO\n";
}
}
This is my first attempt at SFINAE:
#include <type_traits>
#include <iostream>
struct C1 {
using T = int;
};
struct C2 {
using T = void;
};
// For classes that declare T = int
template <class C>
void f(C &c,
std::enable_if<!std::is_same<typename C::T, void>::value, int>::type = 0) {
std::cout << "With T" << std::endl;
}
// For classes that declare T = void
template <class C>
void f(C &c,
std::enable_if<std::is_same<typename C::T, void>::value, int>::type = 0) {
std::cout << "Without T" << std::endl;
}
int main() {
C1 c1;
f(c1); // With T
C2 c2;
f(c2); // Without T
return 0;
}
The compiler (gcc 4.8.2) complains:
‘std::enable_if<!(std::is_same<typename C::T, void>::value), int>::type’ is not a type
What am I doing wrong?
You need a couple of typenames for this to work:
// For classes that declare T = int
template <class C>
void f(C &c,
typename std::enable_if<!std::is_same<typename C::T, void>::value, int>::type = 0) {
std::cout << "With T" << std::endl;
}
// For classes that declare T = void
template <class C>
void f(C &c,
typename std::enable_if<std::is_same<typename C::T, void>::value, int>::type = 0) {
std::cout << "Without T" << std::endl;
}
Or if your compiler supports C++14 you can use std::enable_if_t:
// For classes that declare T = int
template <class C>
void f(C &c,
std::enable_if_t<!std::is_same<typename C::T, void>::value, int> = 0) {
std::cout << "With T" << std::endl;
}
// For classes that declare T = void
template <class C>
void f(C &c,
std::enable_if_t<std::is_same<typename C::T, void>::value, int> = 0) {
std::cout << "Without T" << std::endl;
}
When you defined a template in C++ (with type parameter) you can pass as type actually a pointer to a type, for example:
MyClass<Foo*>... // edited
I wonder if this is really used? Because such question is too broad, let's focus on core C++, meaning -- is it used in STL or Boost? If yes (in STL/Boost) for what purpose?
Please note that I am asking about passing pointer as an argument (from OUTSIDE). Using pointer to passed argument INSIDE template is another story, and I don't ask about that.
Update
The difference between passing a pointer and using a pointer.
Take a look at those posts:
How is vector implemented in C++ and
passing pointer type to template argument .
myname<char*>(...
myname is a function. The type which is passed to template (template, not a function) is pointer to char.
Now, using a pointer inside:
template <class T...
class vector {
private:
T* data_;
You pass an int (for example) but nothing stops the template of using a pointer to it.
I am interested in the first, not the second, case.
A pointer is just a type, so anywhere you can use some_template<T> you might also want to use some_template<T*>
The parts of the standard library based in the STL use std::iterator_traits<Iter> in many places, and Iter might be a pointer type.
Some implementations of std::unique_ptr<T, D> use a data member of type std::tuple<T*, D> (e.g. this is true for GCC's implementation, but this is an implementation detail that you should not care about).
Like I commented, I remembered a use case where functions would be registered as event callbacks by their actual address.
This way the trampoline functions to invoke member functions would be generated statically for each member function registered.
I'm not sure this is something I'd actually have a use for, but it does demonstrate a (contrived?) way in which pointer-to-function template arguments can be used.
#include <iostream>
#include <vector>
const static auto null = nullptr;
template<typename TFuncSignature>
class Callback;
template<typename R, typename A1>
class Callback<R (A1)> {
public:
typedef R (*TFunc)(void*, A1);
Callback() : obj(0), func(0) {}
Callback(void* o, TFunc f) : obj(o), func(f) {}
R operator()(A1 a1) const {
return (*func)(obj, a1);
}
typedef void* Callback::*SafeBoolType;
operator SafeBoolType () const {
return func != 0? &Callback::obj : 0;
}
bool operator! () const {
return func == 0;
}
bool operator== ( const Callback<R (A1)>& right ) const {
return obj == right.obj && func == right.func;
}
bool operator!= ( const Callback<R (A1)>& right ) const {
return obj != right.obj || func != right.func;
}
private:
void* obj;
TFunc func;
};
template<typename R, class T, typename A1>
struct DeduceMemCallbackTag {
template<R (T::*Func)(A1)>
static R Wrapper(void* o, A1 a1) {
return (static_cast<T*>(o)->*Func)(a1);
}
template<R (T::*Func)(A1)>
inline static Callback<R (A1)> Bind(T* o) {
return Callback<R (A1)>(o, &DeduceMemCallbackTag::Wrapper<Func>);
}
};
template<typename R, typename A1>
struct DeduceStaticCallbackTag {
template<R (*Func)(A1)>
static R Wrapper(void*, A1 a1) {
return (*Func)(a1);
}
template<R (*Func)(A1)>
inline static Callback<R (A1)> Bind( ) {
return Callback<R (A1)>( 0, &DeduceStaticCallbackTag::Wrapper<Func> );
}
};
template<typename R, class T, typename A1>
DeduceMemCallbackTag<R, T, A1> DeduceMemCallback(R (T::*)(A1)) {
return DeduceMemCallbackTag<R, T, A1>();
}
template<typename R, typename A1>
DeduceStaticCallbackTag<R, A1> DeduceStaticCallback(R (*)(A1)) {
return DeduceStaticCallbackTag<R, A1>();
}
template <typename T1> class Event {
public:
typedef void(* TSignature)( T1 );
typedef Callback<void( T1 )> TCallback;
protected:
std::vector<TCallback> invocations;
std::vector<Event<T1>*> events;
public:
const static int ExpectedFunctorCount = 2;
Event () : invocations(), events() {
invocations.reserve( ExpectedFunctorCount );
events.reserve( ExpectedFunctorCount );
}
template <void (* TFunc)(T1)> void Add ( ) {
TCallback c = DeduceStaticCallback( TFunc ).template Bind< TFunc >( );
invocations.push_back( c );
}
template <typename T, void (T::* TFunc)(T1)> void Add ( T& object ) {
Add<T, TFunc>( &object );
}
template <typename T, void (T::* TFunc)(T1)> void Add ( T* object ) {
TCallback c = DeduceMemCallback( TFunc ).template Bind< TFunc >( object );
invocations.push_back( c );
}
void Invoke ( T1 t1 ) {
size_t i;
for ( i = 0; i < invocations.size(); ++i ) {
invocations[i]( t1 );
}
for ( i = 0; i < events.size(); ++i ) {
(*events[i])( t1 );
}
}
void operator() ( T1 t1 ) {
Invoke( t1 );
}
size_t InvocationCount ( ) {
return events.size( ) + invocations.size( );
}
template <void (* TFunc)(T1)> bool Remove ( ) {
TCallback target = DeduceStaticCallback( TFunc ).template Bind< TFunc >( );
for ( size_t i = 0; i < invocations.size(); ++i ) {
TCallback& inv = invocations[i];
if ( target == inv ) {
invocations.erase( invocations.begin() + i );
return true;
}
}
return false;
}
template <typename T, void (T::* TFunc)(T1)> bool Remove ( T& object ) {
return Remove<T, TFunc>( &object );
}
template <typename T, void (T::* TFunc)(T1)> bool Remove ( T* object ) {
TCallback target = DeduceMemCallback( TFunc ).template Bind< TFunc >( object );
for ( size_t i = 0; i < invocations.size(); ++i ) {
TCallback& inv = invocations[i];
if ( target == inv ) {
invocations.erase( invocations.begin() + i );
return true;
}
}
return false;
}
};
namespace IntStatic {
void VoidTest () { std::cout << "INTO THE VOID" << std::endl; }
void IntTest (int num) { std::cout << "Got myself a " << num << " !" << std::endl; }
void IntTest2 (int num) { std::cout << "Now _I_ Got myself a " << num << " !" << std::endl; }
}
struct Int {
void Test (int num) { std::cout << num << " on the inside of a class... ?" << std::endl; }
void Test2 (int num) { std::cout << num << " on the inside of a struct, yo !" << std::endl; }
static void Test3(int snum) { std::cout << snum << " on the inside of a class... ?" << std::endl; }
};
int main(int argc, char* argv[]) {
Event<int> intev;
Int i;
intev.Add<Int, &Int::Test>(i);
intev.Add<&IntStatic::IntTest>();
intev.Add<&IntStatic::IntTest2>();
//intev.Add( Int::Test3 );
intev(20);
intev.Remove<&IntStatic::IntTest>();
intev.Remove<&IntStatic::IntTest>();
intev.Remove<Int, &Int::Test>(i);
//intev.Remove( Int::Test3 );
//intev.Remove( i, &Int::Test );
intev(20);
return 0;
}
The actual code is famously written by #ThePhD, credits to him. See it Live on Coliru
You could have different semantics by specialization, e.g.:
template <typename T> struct referred_sizeof {
static constexpr size_t value = sizeof(T);
};
Now, this could be specialized:
template <typename T> struct referred_sizeof<T*> {
static constexpr size_t value = sizeof(T);
};
template <typename T> struct referred_sizeof <boost::optional<T*> > {
static constexpr size_t value = sizeof(boost::optional<T*>) + sizeof(T);
};
Which makes the behaviour:
static_assert(referred_sizeof <int>::value == referred_sizeof <int*>::value, "passes");
This application is what others referred to in comments as implementing traits classes.
Full sample, adding specialization for boost::tuple<...> just for fun: See it Live On Coliru
int main()
{
report<double>();
report<double *>();
report<boost::optional<double> >();
report<boost::optional<double> *>();
report<boost::optional<double *> *>();
report<boost::tuple<boost::optional<double *> *, double> >();
}
Prints
void report() [with T = double]: referred_sizeof is 8
void report() [with T = double*]: referred_sizeof is 8
void report() [with T = boost::optional<double>]: referred_sizeof is 16
void report() [with T = boost::optional<double>*]: referred_sizeof is 16
void report() [with T = boost::optional<double*>*]: referred_sizeof is 24
void report() [with T = boost::tuples::tuple<boost::optional<double*>*, double>]: referred_sizeof is 40
Full implementation for reference
#include <iostream>
#include <boost/optional.hpp>
#include <boost/tuple/tuple.hpp>
template <typename... Ts> struct referred_sizeof;
// base cases
template <typename T> struct referred_sizeof<T> {
static constexpr size_t value = sizeof(T);
};
template <typename T> struct referred_sizeof<T*> {
static constexpr size_t value = referred_sizeof<T>::value;
};
template <typename T> struct referred_sizeof<boost::optional<T*> > {
static constexpr size_t value = sizeof(boost::optional<T*>) + referred_sizeof<T>::value;
};
template <typename... Ts> struct referred_sizeof<boost::tuple<Ts...> > {
static constexpr size_t value = referred_sizeof<Ts...>::value; // TODO take into account padding/alignment overhead?
};
static_assert(referred_sizeof<int>::value == referred_sizeof<int*>::value, "passes");
template <typename T1, typename... Ts> struct referred_sizeof<T1, Ts...> {
static constexpr size_t value = referred_sizeof<T1>::value + referred_sizeof<Ts...>::value;
};
template <typename T>
void report()
{
std::cout << __PRETTY_FUNCTION__ << ": referred_sizeof is " << referred_sizeof<T>::value << "\n";
}