I have a working functor_wrapper class for 2 parameters that I'm having trouble generalising into variadic template parameters.
In particular, I'm having trouble getting the syntax right while converting this line in 2 parameters to variadics:
2 Parameter CODE
return m_cb( dynamic_cast<T const&>( t ), dynamic_cast<U const&>( u ));
Broken Variadic CODE
return m_cb( dynamic_cast<I const&>( t ),
dynamic_cast<typename... const& Cs>( u... ));
For anyone who wants to know, this wrapper class is part of a multiple_dispatch class. In order to provide a common type/interface to the client, I have this Functor_Wrapper class and operator() that takes the parent class type. When dispatching, I downcast by dynamic_cast<>ing the parameters down to the correct types.
UPDATE
I just realised that I have another problem: my virtual operator() in my Parent_Functor_Wrapper needs to be converted to n parameters of P const& so I need to unroll the signature somehow!
The same applies to the concrete implementation of operator() in Functor_Wrapper.
UPDATE 2
Posting complete code so the programming context can be better understood.
UPDATE 3
Accepting ildjam's answer because it addresses the original problem. I need to think some more about how to deal with the pure virtual operator(). Meanwhile, the code below works fine if you comment out #define USE_VARIADICS, and run the hard-coded version. I will post a separate question if I cannot resolve this issue.
CODE
#include <typeinfo>
#include <functional>
#include <stdexcept>
#include <cassert>
#include <map>
#include <array>
#include <iostream>
#define USE_VARIADICS
#ifdef USE_VARIADICS
template<typename P,typename R,typename... Cs>
struct Parent_Functor_Wrapper
{
using cb_func = std::function<R(P const&, P const& )>;
virtual R operator()( P const&, P const& ) = 0;
};
// parent class, return type, concrete classes...
template<typename P,typename R,typename I,typename... Cs>
struct Functor_Wrapper :
public Parent_Functor_Wrapper<P,R,Cs...>
{
using cb_func = std::function<R(I const&, Cs const& ...)>;
cb_func m_cb;
// dynamic_cast<typename... const& Cs>( u... ) -> dynamic_cast<Cs const&>(u)...
Functor_Wrapper( cb_func cb ) : m_cb( cb ) { }
virtual R operator()( P const& t, Cs const& ... u ) override
{
return m_cb( dynamic_cast<I const&>( t ),
dynamic_cast<Cs const&>( u )...);
}
};
#else
template<typename P,typename R>
struct Parent_Functor_Wrapper
{
using cb_func = std::function<R(P const&, P const& )>;
virtual R operator()( P const&, P const& ) = 0;
};
template<typename P,typename R,typename T,typename U>
struct Functor_Wrapper :
public Parent_Functor_Wrapper<P,R>
{
using cb_func = std::function<R(T const&, U const&)>;
cb_func m_cb;
Functor_Wrapper( cb_func cb ) : m_cb( cb ) { }
virtual R operator()( P const& t, P const& u ) override
{
return m_cb( dynamic_cast<T const&>( t ), dynamic_cast<U const&>( u ));
}
};
#endif
template<typename T,unsigned N>
struct n_dimension
{
using type = typename n_dimension<T,N-1>::type;
};
template<typename T>
struct n_dimension<T,1>
{
using type = std::tuple<T>;
};
template<typename K>
K gen_key( K* p=nullptr, size_t idx=0 )
{
return *p;
};
template<typename K,typename T,typename... Ts>
K gen_key( K* p=nullptr, size_t idx=0 )
{
K m_instance;
if ( p==nullptr )
p = &m_instance;
*(p->begin() + idx) = typeid( T ).hash_code();
gen_key<K,Ts...>( p, ++idx );
return m_instance;
};
template<typename F,typename P,typename... Cs>
struct multiple_dispatcher { multiple_dispatcher() { } };
template<typename F,typename P,typename I,typename... Cs>
struct multiple_dispatcher<F,P,I,Cs...>
{
using functor_type = Parent_Functor_Wrapper<P,std::string>;
using key_type = std::array<size_t,F::n_dimension::val>;
using map_type = std::map<key_type,functor_type*>;
using value_type = typename map_type::value_type;
map_type m_jump_table;
multiple_dispatcher( std::initializer_list<value_type> const& cb_mapping )
{
for( const auto& p : cb_mapping )
m_jump_table.insert( p );
}
template< typename T, typename U >
typename F::return_type operator()( T& x, U& y )
{
auto k = key_type{ { x.get_id(), y.get_id() } };
auto func = m_jump_table.at( k );
return (*func)( x, y );
}
size_t size() const { return m_jump_table.size(); }
};
// =============================================================================
struct A { virtual ~A() { }
virtual size_t get_id() const { return typeid( A ).hash_code(); }
};
struct B : public A { virtual ~B() { }
virtual size_t get_id() const override { return typeid( B ).hash_code(); }
};
struct C : public A { int x; virtual ~C() { }
virtual size_t get_id() const override { return typeid( C ).hash_code(); }
};
struct Functor_Pairs
{
using return_type = std::string;
enum n_dimension { val = 2 };
static std::string MyFn(A const& arg1, A const& arg2) { return "A,A"; }
static std::string MyFn(A const& arg1, B const& arg2) { return "A,B"; }
static std::string MyFn(A const& arg1, C const& arg2) { return "A,C"; }
static std::string MyFn(B const& arg1, A const& arg2) { return "B,A"; }
static std::string MyFn(B const& arg1, B const& arg2) { return "B,B"; }
static std::string MyFn(B const& arg1, C const& arg2) { return "B,C"; }
static std::string MyFn(C const& arg1, A const& arg2) { return "C,A"; }
static std::string MyFn(C const& arg1, B const& arg2) { return "C,B"; }
static std::string MyFn(C const& arg1, C const& arg2) { return "C,C"; }
};
// =============================================================================
std::string (*MyFun_aa)(A const&, A const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_ab)(A const&, B const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_ac)(A const&, C const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_ba)(B const&, A const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_bb)(B const&, B const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_bc)(B const&, C const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_ca)(C const&, A const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_cb)(C const&, B const&) = &Functor_Pairs::MyFn;
std::string (*MyFun_cc)(C const&, C const&) = &Functor_Pairs::MyFn;
Functor_Wrapper<A,std::string,A,A> w_aa( MyFun_aa );
Functor_Wrapper<A,std::string,A,B> w_ab( MyFun_ab );
Functor_Wrapper<A,std::string,A,C> w_ac( MyFun_ac );
Functor_Wrapper<A,std::string,B,A> w_ba( MyFun_ba );
Functor_Wrapper<A,std::string,B,B> w_bb( MyFun_bb );
Functor_Wrapper<A,std::string,B,C> w_bc( MyFun_bc );
Functor_Wrapper<A,std::string,C,A> w_ca( MyFun_ca );
Functor_Wrapper<A,std::string,C,B> w_cb( MyFun_cb );
Functor_Wrapper<A,std::string,C,C> w_cc( MyFun_cc );
// =============================================================================
int main( int argc, char* argv[] )
{
B b;
C c;
A& arg1 = b;
A& arg2 = c;
using md_type = multiple_dispatcher<Functor_Pairs,A,B,C>;
using K = md_type::key_type;
md_type md
{
std::make_pair( gen_key<K,A,A>(), &w_aa ),
std::make_pair( gen_key<K,A,B>(), &w_ab ),
std::make_pair( gen_key<K,A,C>(), &w_ac ),
std::make_pair( gen_key<K,B,A>(), &w_ba ),
std::make_pair( gen_key<K,B,B>(), &w_bb ),
std::make_pair( gen_key<K,B,C>(), &w_bc ),
std::make_pair( gen_key<K,C,A>(), &w_ca ),
std::make_pair( gen_key<K,C,B>(), &w_cb ),
std::make_pair( gen_key<K,C,C>(), &w_cc )
};
std::cerr << "N = " << md.size() << std::endl;
std::cerr << "RESULT = " << md( arg1, arg2 ) << std::endl;
assert( !std::string( "B,C" ).compare( md( arg1, arg2 )) );
#if 0
std::cerr << typeid( A ).hash_code() << std::endl;
std::cerr << typeid( B ).hash_code() << std::endl;
std::cerr << typeid( C ).hash_code() << std::endl;
#endif
return 0;
}
You need to change:
dynamic_cast<typename... const& Cs>( u... )
to:
dynamic_cast<Cs const&>( u )...
The former (invalid syntax aside) is attempting to expand Cs into a single dynamic_cast while the latter expands each type in Cs into its own dynamic_cast.
That being said, I don't think your override will work since your base's operator() signature is R operator()( P const&, P const& ) and your derived's signature is not (unless Cs const&... coincidentally happens to expand into P const&)…
Related
I want to store a pair of member get/set functions for later use with an object of type T.
I have a partially working setup, see below. Questions remain however:
How do I (smartly) deal with all possible variants? member_get could be [returning value or const value& or even value& | const or non-const] member_set could be [accepting const &, & or &&]. Sure, 'best practices' would rule out some combinations, but I cannot rely on that as the definition of member_get and member_set is out of my hands.
How do I correctly deal with possible member_set move semantics?
Is there a different/better/simpler general way to approach this?
Notes:
I intentionally left open the exact type S of the setter. Not sure if that's a good or bad idea.
Lambdas obviously come to mind, but I can't see how they can help the issue. The caller of Make( get, set ) is not supposed to supply lambdas. That would be just delegating the problem to him!?
any std::function ideas should be ruled out because of the overhead
template <typename T, typename V, typename G, typename S>
class GetSet
{
public:
constexpr GetSet( G member_get, S member_set ) : Get( member_get ), Set( member_set )
{ }
auto GetValue( const T& t ) const
{
return ( t.*Get )( );
}
void SetValue( T& t, V&& value ) const
{
( t.*Set )( std::forward<V>( value ) );
}
private:
G Get;
S Set;
};
template <typename T, typename ValueType, typename S>
constexpr auto Make( ValueType( T::*member_get )( ) const, S member_set )
{
using G = ValueType( T::* )( ) const;
return GetSet<T, ValueType, G, S>( member_get, member_set );
}
Not sure why you need this, but the simplest solution is below.
#include <utility>
template <class F> struct ClassType;
template <typename Ret, typename TCls, typename... Args>
struct ClassType<Ret (TCls::*)(Args...)> {
using type = TCls;
};
template <typename Ret, typename TCls>
struct ClassType<Ret (TCls::*)() const> {
using type = TCls;
};
template<class TFnGet, class TFnSet>
class GetSet
{
public:
using TGet = TFnGet;
using TSet = TFnSet;
public:
inline GetSet(TGet fnGet, TSet fnSet)
: m_fnGet(fnGet), m_fnSet(fnSet)
{
}
template<class T>
inline decltype(auto) GetValue(T&& r) const
{
static_assert(std::is_same<typename std::remove_cv<typename std::remove_reference<T>::type>::type, typename ClassType<TFnGet>::type>::value, "wrong type of r?");
return (r.*m_fnGet)();
}
template<class T, class TValue>
inline void SetValue(T&& r, TValue&& value)
{
static_assert(std::is_same<typename std::remove_cv<typename std::remove_reference<T>::type>::type, typename ClassType<TFnSet>::type>::value, "wrong type of r?");
(r.*m_fnSet)(std::forward<TValue>(value));
}
private:
TGet m_fnGet;
TSet m_fnSet;
};
template<class TGet, class TSet>
GetSet<TGet, TSet> MakeGetSet(TGet fnGet, TSet fnSet)
{
static_assert(std::is_same<typename ClassType<TGet>::type, typename ClassType<TSet>::type>::value, "members of different classes?");
return GetSet<TGet, TSet>(fnGet, fnSet);
}
verified with:
class A
{
public:
void Set(int i) {}
int Get() const { return 0;}
void SetRef(char& ch) {}
A& GetRef() { return *this;}
void SetRRef(float&& ) {}
int&& GetRRef() { return 1; }
void SetConstRef(const char& ch) {}
int GetNotConst() { return 0;}
};
int main(int argc, char* argv[])
{
A a;
auto gs = MakeGetSet(&A::Get, &A::Set);
auto gsRef = MakeGetSet(&A::GetRef, &A::SetRef);
auto gs2 = MakeGetSet(&A::GetRRef, &A::SetRRef);
auto gsNonConst = MakeGetSet(&A::GetNotConst, &A::SetConstRef);
int x = gs.GetValue(a);
gs.SetValue(a, 2);
const A& ra = a;
x = gs.GetValue(ra);
A& r = gsRef.GetValue(a);
char ch =' ';
gsRef.SetValue(a, ch);
x = gs2.GetValue(a);
gs2.SetValue(a, 1.1f);
x = gsNonConst.GetValue(a);
gsNonConst.SetValue(a, ch);
std::cout << "ok\n";
return 0;
}
How to handle an api which returns different data types for the same input data types?
Looking at the below example, apicall should return a date or a string depending on the input attribute:
#include <iostream>
#include <string>
using namespace std;
???? apicall(string datatype, string attribute)
{
// code
}
int main(int argc, char** argv)
{
string datatype = "Thomas"
string attribute = "bithday"
cout << apicall(datatype, attribute) << endl;
string datatype = "Thomas"
string attribute = "address"
cout << apicall(datatype, attribute) << endl;
}
What could be in place of ???? (apicall return datatype) and how to handle these cases?
I am trying to understand these concepts as my experience to date has been with duck typed scripting languages.
The ideal solution is to use a std::variant, which is a safe union type like.
This allows you to write the following:
using DateOrString = std::variant<DateType, std::string>;
DateOrString api_call(std::string, std::string) {
// you can return both DateType and std::string
}
// ...
auto result = api_call("", "");
auto& str = std::get<std::string>(result);
Unfortunately std::variant is a C++17 feature. However different compilers already support it.
As already has been suggested, boost has a variant class and you can use it with any C++ standard.
As last option, you may implement a "variant-like" class which handles both a date and a string. Your function should return it.
Here a demo how to quickly implement that kind of class.
Note that that class is safe because the type is checked at runtime.
As a variant object, your callee function should branch on the type, something like:
auto result = api_call(/*...*/);
if (result.is_string()) {
// result is a string
const auto& str = result.get_string();
} else {
// result is a date
const auto& date = result.get_date();
}
... returns different data types for the same input data types?
This is literally impossible. A function is defined with one (or zero) return types, and zero or more input parameter types.
The workarounds are:
Write a single function returning a variant type, such as std::variant in C++17, or Boost.Variant if that's not available.
Write multiple functions with different return types (the caller just has to choose the right one)
Invert control, so that instead of returning a value, you pass an object capable of processing all the required types:
struct APIHandler {
virtual ~APIHandler() {}
virtual void operator()(int) {}
virtual void operator()(string) {}
};
void apicall(string name, string attr, APIHandler &h) {
// dummy implementation
if (attr == "address") {
h("123 Woodford Road");
} else if (attr == "birthday") {
h(19830214);
}
}
// implement your type-specific logic here
struct MyHandler: APIHandler {
void operator()(int i) override {
cout << "got an int:" << i << '\n';
}
void operator()(string s) override {
cout << "got a string:" << s << '\n';
}
};
// and use it like:
MyHandler mh;
apicall("Thomas", "birthday", mh);
apicall("Thomas", "address", mh);
You want a std::variant in C++17 or a boost::variant or roll your own crude variant something like this:
constexpr std::size_t max() { return 0; }
template<class...Ts>
constexpr std::size_t max( std::size_t t0, Ts...ts ) {
return (t0<max(ts...))?max(ts...):t0;
}
template<class T0, class...Ts>
struct index_of_in;
template<class T0, class...Ts>
struct index_of_in<T0, T0, Ts...>:std::integral_constant<std::size_t, 0> {};
template<class T0, class T1, class...Ts>
struct index_of_in<T0, T1, Ts...>:
std::integral_constant<std::size_t,
index_of_in<T0, Ts...>::value+1
>
{};
struct variant_vtable {
void(*dtor)(void*) = 0;
void(*copy)(void*, void const*) = 0;
void(*move)(void*, void*) = 0;
};
template<class T>
void populate_vtable( variant_vtable* vtable ) {
vtable->dtor = [](void* ptr){ static_cast<T*>(ptr)->~T(); };
vtable->copy = [](void* dest, void const* src){
::new(dest) T(*static_cast<T const*>(src));
};
vtable->move = [](void* dest, void* src){
::new(dest) T(std::move(*static_cast<T*>(src)));
};
}
template<class T>
variant_vtable make_vtable() {
variant_vtable r;
populate_vtable<T>(&r);
return r;
}
template<class T>
variant_vtable const* get_vtable() {
static const variant_vtable table = make_vtable<T>();
return &table;
}
template<class T0, class...Ts>
struct my_variant {
std::size_t index = -1;
variant_vtable const* vtable = 0;
static constexpr auto data_size = max(sizeof(T0),sizeof(Ts)...);
static constexpr auto data_align = max(alignof(T0),alignof(Ts)...);
template<class T>
static constexpr std::size_t index_of() {
return index_of_in<T, T0, Ts...>::value;
}
typename std::aligned_storage< data_size, data_align >::type data;
template<class T>
T* get() {
if (index_of<T>() == index)
return static_cast<T*>((void*)&data);
else
return nullptr;
}
template<class T>
T const* get() const {
return const_cast<my_variant*>(this)->get<T>();
}
template<class F, class R>
using applicator = R(*)(F&&, my_variant*);
template<class T, class F, class R>
static applicator<F, R> get_applicator() {
return [](F&& f, my_variant* ptr)->R {
return std::forward<F>(f)( *ptr->get<T>() );
};
}
template<class F, class R=typename std::result_of<F(T0&)>::type>
R visit( F&& f ) & {
if (index == (std::size_t)-1) throw std::invalid_argument("variant");
static const applicator<F, R> table[] = {
get_applicator<T0, F, R>(),
get_applicator<Ts, F, R>()...
};
return table[index]( std::forward<F>(f), this );
}
template<class F,
class R=typename std::result_of<F(T0 const&)>::type
>
R visit( F&& f ) const& {
return const_cast<my_variant*>(this)->visit(
[&f](auto const& v)->R
{
return std::forward<F>(f)(v);
}
);
}
template<class F,
class R=typename std::result_of<F(T0&&)>::type
>
R visit( F&& f ) && {
return visit( [&f](auto& v)->R {
return std::forward<F>(f)(std::move(v));
} );
}
explicit operator bool() const { return vtable; }
template<class T, class...Args>
void emplace( Args&&...args ) {
clear();
::new( (void*)&data ) T(std::forward<Args>(args)...);
index = index_of<T>();
vtable = get_vtable<T>();
}
void clear() {
if (!vtable) return;
vtable->dtor( &data );
index = -1;
vtable = nullptr;
}
~my_variant() { clear(); }
my_variant() {}
void copy_from( my_variant const& o ) {
if (this == &o) return;
clear();
if (!o.vtable) return;
o.vtable->copy( &data, &o.data );
vtable = o.vtable;
index = o.index;
}
void move_from( my_variant&& o ) {
if (this == &o) return;
clear();
if (!o.vtable) return;
o.vtable->move( &data, &o.data );
vtable = o.vtable;
index = o.index;
}
my_variant( my_variant const& o ) {
copy_from(o);
}
my_variant( my_variant && o ) {
move_from(std::move(o));
}
my_variant& operator=(my_variant const& o) {
copy_from(o);
return *this;
}
my_variant& operator=(my_variant&& o) {
move_from(std::move(o));
return *this;
}
template<class T,
typename std::enable_if<!std::is_same<typename std::decay<T>::type, my_variant>{}, int>::type =0
>
my_variant( T&& t ) {
emplace<typename std::decay<T>::type>(std::forward<T>(t));
}
};
then your code looks like:
variant<string, int> apicall(string datatype, string attribute)
{
if (datatype > attribute) return string("hello world");
return 7;
}
int main()
{
string datatype = "Thomas"
string attribute = "bithday"
apicall(datatype, attribute).visit([](auto&&r){
cout << r << endl;
});
string datatype = "Thomas"
string attribute = "address"
apicall(datatype, attribute).visit([](auto&& r){
cout << r << endl;
});
}
with whatever visit or apply_visitor free function or method your particular variant supports.
This gets much more annoying in C++11 as we don't have generic lambdas.
You could use a variant, but it's up to the caller site to check the results. Boost and std defines two variant types, i.e. std::variant and std::any.
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";
}
I've read the various authorities on this, include Dewhurst and yet haven't managed to get anywhere with this seemingly simple question.
What I want to do is to call a C++ function object, (basically, anything you can call, a pure function or a class with ()), and return its value, if that is not void, or "true" otherwise.
using std:
struct Foo {
void operator()() { cout << "Foo/"l; }
};
struct Bar {
bool operator()() { cout << "Bar/"; return true; }
};
Foo foo;
Bar bar;
bool baz() { cout << "baz/"; return true; }
void bang() { cout << "bang/"; }
const char* print(bool b) { cout << b ? "true/" : "false/"; }
template <typename Functor> bool magicCallFunction(Functor f) {
return true; // Lots of template magic occurs here
// that results in the functor being called.
}
int main(int argc, char** argv) {
print(magicCallFunction(foo));
print(magicCallFunction(bar));
print(magicCallFunction(baz));
print(magicCallFunction(bang));
printf("\n");
}
// Results: Foo/true/Bar/true/baz/true/bang/true
UPDATE
Thanks for the thoughts and ideas!
Based on this, I actually decided to bring up all my templating one level - so instead I have:
bool eval(bool (*f)()) { return (*f)(); }
bool eval(void (*f)()) { (*f)(); return true; }
template <typename Type>
bool eval(Type* obj, bool (Type::*method)()) { return (obj->*method)(); }
template <typename Type>
bool eval(Type* obj, void (Type::*method)()) { (obj->*method)(); return true; }
and generic classes to carry the various objects and methods around. Thanks to Mr.Ree for the code that pushed me in that direction!
To detect a void return value at compile time, the standard trick is to overload operator,. The cool thing with the comma operator is that it can take a void parameter, and in this case it defaults to the built in operator,. In code:
template <typename> tag {};
template <typename T>
tag<T> operator,(T, tag<void>);
Now, expr, tag<void>() has type tag<typeof(expr)> even if expr has type void. You can then catch this with usual tricks:
char (&test(tag<void>))[1];
template <typename T> char (&test(tag<T>))[2];
template <typename F>
struct nullary_functor_traits
{
static const bool returns_void = sizeof(test((factory()(), tag<void>()))) == 1;
private:
static F factory();
};
Wouldn't it be easier to implement an overloaded no-op version of print(void)?
Ahh well. Function templates and overloading will easily handle this at runtime.
It gets somewhat stickier if you had wanted to handle this at compile time, for use with #if macros or static-compile-time-asserts.
But since you only want the former, may I suggest something like this as a starting point:
(Tested under (GCC) 3.4.4 & 4.0.1. -- I know, I need to upgrade!)
#include <iostream>
using namespace std;
struct Foo {
void operator()() {}
};
struct Bar {
bool operator()() { return false; }
};
Foo foo;
Bar bar;
bool baz() { return false; }
void bang() {}
struct IsVoid
{
typedef char YES[1];
typedef char NO[2];
/* Testing functions for void return value. */
template <typename T>
static IsVoid::NO & testFunction( T (*f)() );
static IsVoid::YES & testFunction( void (*f)() );
static IsVoid::NO & testFunction( ... );
/* Testing Objects for "void operator()()" void return value. */
template <typename C, void (C::*)()>
struct hasOperatorMethodStruct { };
template <typename C>
static YES & testMethod( hasOperatorMethodStruct<C, &C::operator()> * );
template <typename C>
static NO & testMethod( ... );
/* Function object method to call to perform test. */
template <typename T>
bool operator() (T & t)
{
return ( ( sizeof(IsVoid::testFunction(t)) == sizeof(IsVoid::YES) )
|| ( sizeof(IsVoid::testMethod<T>(0)) == sizeof(IsVoid::YES) ) );
}
};
#define BOUT(X) cout << # X " = " << boolToString(X) << endl;
const char * boolToString( int theBool )
{
switch ( theBool )
{
case true: return "true";
case false: return "false";
default: return "unknownvalue";
}
}
int main()
{
IsVoid i;
BOUT( IsVoid()(foo) );
BOUT( IsVoid()(bar) );
BOUT( IsVoid()(baz) );
BOUT( IsVoid()(bang) );
cout << endl;
BOUT( i(foo) );
BOUT( i(bar) );
BOUT( i(baz) );
BOUT( i(bang) );
}
Okay, I begin to see more of the problem.
While we can do something along the lines of this:
#include <iostream>
using namespace std;
struct FooA {
void operator()() {}
};
struct FooB {
bool operator()() { return false; }
};
struct FooC {
int operator()() { return 17; }
};
struct FooD {
double operator()() { return 3.14159; }
};
FooA fooA;
FooB fooB;
FooC fooC;
FooD fooD;
void barA() {}
bool barB() { return false; }
int barC() { return 17; }
double barD() { return 3.14159; }
namespace N
{
/* Functions */
template <typename R>
R run( R (*f)() ) { return (*f)(); }
bool run( void (*f)() ) { (*f)(); return true; }
/* Methods */
template <typename T, typename R>
R run( T & t, R (T::*f)() ) { return (t .* f) (); }
template <typename T>
bool run( T & t, void (T::*f)() ) { (t .* f) (); return true; }
};
#define SHOW(X) cout << # X " = " << (X) << endl;
#define BOUT(X) cout << # X " = " << boolToString(X) << endl;
const char * boolToString( int theBool )
{
switch ( theBool )
{
case true: return "true";
case false: return "false";
default: return "unknownvalue";
}
}
int main()
{
SHOW( N::run( barA ) );
BOUT( N::run( barA ) );
SHOW( N::run( barB ) );
BOUT( N::run( barB ) );
SHOW( N::run( barC ) );
SHOW( N::run( barD ) );
cout << endl;
SHOW( N::run(fooA,&FooA::operator()));
BOUT( N::run(fooA,&FooA::operator()));
SHOW( N::run(fooB,&FooB::operator()));
BOUT( N::run(fooB,&FooB::operator()));
SHOW( N::run(fooC,&FooC::operator()));
SHOW( N::run(fooD,&FooD::operator()));
}
You do still have that nasty need to feed &CLASS::operator() in as an argument.
Ultimately, while we can determine whether the object's operator() method returns a void, we cannot normally overload based on return types.
We can get around that overloading limitation via template specialization. But then we get into this uglyness wherein we still need to specify types... Especially the return type! Either manually, or by passing in a suitable argument from which we can extract the necessary types.
BTW: #define macros won't help either. Tools like ?: require the same type for both the ? and : part.
So this is the best I can do...
Of course...
If you don't need the return type...
If you are just passing the result to another function...
You can do something like this:
#include <iostream>
using namespace std;
struct FooA {
void operator()() {}
};
struct FooB {
bool operator()() { return false; }
};
struct FooC {
int operator()() { return 17; }
};
struct FooD {
double operator()() { return 3.14159; }
};
FooA fooA;
FooB fooB;
FooC fooC;
FooD fooD;
void barA() {}
bool barB() { return false; }
int barC() { return 17; }
double barD() { return 3.14159; }
#define SHOW(X) cout << # X " = " << (X) << endl;
namespace N
{
template <typename T, typename R>
R run( T & t, R (T::*f)() ) { return (t .* f) (); }
template <typename T>
bool run( T & t, void (T::*f)() ) { (t .* f) (); return true; }
template <typename T>
void R( T & t )
{
SHOW( N::run( t, &T::operator() ) );
}
template <typename T>
void R( T (*f)() )
{
SHOW( (*f)() );
}
void R( void (*f)() )
{
(*f)();
SHOW( true );
}
};
int main()
{
N::R( barA );
N::R( barB );
N::R( barC );
N::R( barD );
N::R( fooA );
N::R( fooB );
N::R( fooC );
N::R( fooD );
}
Perhaps you can use the fact that void& does not make sense as type but void* makes.
With C++0x you could do that easily by using decltype.
If you can use Boost, the following code will serve probably.
I presume all the functions/functors are nullary as in your question.
However, in order to use this, result_type has to be defined in
all the functors(function class).
#include <boost/utility/result_of.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
using namespace boost; // Sorry, for brevity
template< class F >
// typename result_of< F() >::type
typename disable_if<
is_void< typename result_of< F() >::type >
, typename result_of< F() >::type
>::type
f( F const& x )
{
return x();
}
template< class F >
typename enable_if<
is_void< typename result_of< F() >::type >, bool
>::type
f( F const& x )
{
x();
return true;
}
template< class T >
T f( T x() )
{
return x();
}
bool f( void x() )
{
x();
return true;
}
static void void_f() {}
static int int_f() { return 1; }
struct V {
typedef void result_type;
result_type operator()() const {}
};
struct A {
typedef int result_type;
result_type operator()() const { return 1; }
};
int main()
{
A a;
V v;
f( void_f );
f( int_f );
f( a );
f( v );
}
Hope this helps
try to specialize for void return type:
template<class F>
class traits;
template<class F, class T>
class traits<T (F)()>;
template<class F>
class traits<void (F)()>;
i think ...
I am a newer for C++, and my first language is Chinese, so my words with English may be unmeaningful, say sorry first.
I know there is a way to write a function with variable parameters which number or type maybe different each calling, we can use the macros of va_list,va_start and va_end. But as everyone know, it is the C style. When we use the macros, we will lose the benefit of type-safe and auto-inference, then I try do it whit C++ template. My work is followed:
#include<iostream>
#include<vector>
#include<boost/any.hpp>
struct Argument
{
typedef boost::bad_any_cast bad_cast;
template<typename Type>
Argument& operator,(const Type& v)
{
boost::any a(v);
_args.push_back(a);
return *this;
}
size_t size() const
{
return _args.size();
}
template<typename Type>
Type value(size_t n) const
{
return boost::any_cast<Type>(_args[n]);
}
template<typename Type>
const Type* piont(size_t n) const
{
return boost::any_cast<Type>(&_args[n]);
}
private:
std::vector<boost::any> _args;
};
int sum(const Argument& arg)
{
int sum=0;
for(size_t s=0; s<arg.size(); ++s)
{
sum += arg.value<int>(s);
}
return sum;
}
int main()
{
std::cout << sum((Argument(), 1, 3, 4, 5)) << std::endl;
return 0;
}
I think it's ugly, I want to there is a way to do better? Thanks, and sorry for language errors.
You can do something like this:
template <typename T>
class sum{
T value;
public:
sum ()
: value() {};
// Add one argument
sum<T>& operator<<(T const& x)
{ value += x; return *this; }
// to get funal value
operator T()
{ return value;}
// need another type that's handled differently? Sure!
sum<T>& operator<<(double const& x)
{ value += 100*int(x); return *this; }
};
#include <iostream>
int main()
{
std::cout << (sum<int>() << 5 << 1 << 1.5 << 19) << "\n";
return 0;
}
Such technique (operator overloading and stream-like function class) may solve different problems with variable arguments, not only this one. For example:
create_window() << window::caption - "Hey" << window::width - 5;
// height of the window and its other parameters are not set here and use default values
After giving it some thought, I found a way to do it using a typelist. You don't need an any type that way, and your code becomes type-safe.
It's based on building a template structure containing a head (of a known type) and a tail, which is again a typelist. I added some syntactic sugar to make it more intuitive: use like this:
// the 1 argument processing function
template< typename TArg > void processArg( const TArg& arg ) {
std::cout << "processing " << arg.value << std::endl;
}
// recursive function: processes
// the first argument, and calls itself again for
// the rest of the typelist
// (note: can be generalized to take _any_ function
template< typename TArgs >
void process( const TArgs& args ) {
processArg( args.head );
return process( args.rest );
}
template<> void process<VoidArg>( const VoidArg& arg ){}
int main() {
const char* p = "another string";
process( (arglist= 1, 1.2, "a string", p ) );
}
And here is the argument passing framework:
#include <iostream>
// wrapper to abstract away the difference between pointer types and value types.
template< typename T > struct TCont {
T value;
TCont( const T& t ):value(t){}
};
template<typename T, size_t N> struct TCont< T[N] > {
const T* value;
TCont( const T* const t ) : value( t ) { }
};
template<typename T> struct TCont<T*> {
const T* value;
TCont( const T* t ): value(t){}
};
// forward definition of type argument list
template< typename aT, typename aRest >
struct TArgList ;
// this structure is the starting point
// of the type safe variadic argument list
struct VoidArg {
template< typename A >
struct Append {
typedef TArgList< A, VoidArg > result;
};
template< typename A >
typename Append<A>::result append( const A& a ) const {
Append<A>::result ret( a, *this );
return ret;
}
//syntactic sugar
template< typename A > typename Append<A>::result operator=( const A& a ) const { return append(a); }
} const arglist;
// typelist containing an argument
// and the rest of the arguments (again a typelist)
//
template< typename aT, typename aRest >
struct TArgList {
typedef aT T;
typedef aRest Rest;
typedef TArgList< aT, aRest > Self;
TArgList( const TCont<T>& head, const Rest& rest ): head( head ), rest( rest ){}
TCont<T> head;
Rest rest;
template< typename A > struct Append {
typedef TArgList< T, typename Rest::Append<A>::result > result;
};
template< typename A >
typename Append< A >::result append( const A& a ) const {
Append< A >::result ret ( head.value, (rest.append( a ) ) );
return ret;
}
template< typename A > typename Append<A>::result operator,( const A& a ) const { return append(a); }
};