评论有点长,所以我将其发布为答案:
class EG
{
template<class T>
std::function<void(T)> f; // a data member template?
template<class T>
void func(std::function<void(T)>&& arg)
{
f = nullptr;
f.swap(arg);
// could as well just
// f = std::move(arg);
}
};
如果您的用例是:
EG obj;
obj.func( [](int i) { std::cout << i; } );
obj.f(42);
obj.func( [](string s) { std::cout << s; } );
obj.f("hello world");
这很容易出错,因为编译器无法检查函数调用obj.f
的参数类型,因为参数类型应该是可变的:如果你分配一个void(int)
via obj.func
,那么它应该接受一个 int;如果您分配 a void(string)
,它将接受一个字符串。
C++ 中没有数据成员模板(IMO 拥有它们没有意义——何时应该实例化它们?),但可以获得上述用例的行为。
一个更简单、不易出错的解决方案:
#include <functional>
#include <string>
#include <iostream>
#include <memory>
using std::string;
struct any_function
{
virtual ~any_function()
{}
};
template < typename T >
struct concrete_function
: public any_function
{
T m;
concrete_function(T&& p)
: m( std::move(p) )
{}
virtual ~concrete_function() override
{}
};
struct EG
{
private:
std::shared_ptr<any_function> fs;
public:
EG& operator=(std::function<void(int)>&& p) // do NOT templatize this!!!!
{
using stor_type = concrete_function< std::function<void(int)> >;
fs = std::make_shared<stor_type>( std::move(p) );
return *this;
}
EG& operator=(std::function<void(string)>&& p) // do NOT templatize this!!!!
{
using stor_type = concrete_function< std::function<void(string)> >;
fs = std::make_shared<stor_type>( std::move(p) );
return *this;
}
void operator()(int p) // do NOT templatize this!!!!
{
using stor_type = concrete_function< std::function<void(int)> >;
auto const& ptr = std::static_pointer_cast< stor_type >(fs);
if(ptr) { ptr->m(p); }
else { /* throw something */ }
}
void operator()(string p) // do NOT templatize this!!!!
{
using stor_type = concrete_function< std::function<void(string)> >;
auto const& ptr = std::static_pointer_cast< stor_type >(fs);
if(ptr) { ptr->m(p); }
else { /* throw something */ }
}
};
int main()
{
EG obj;
obj = [](int i) { std::cout << i; };
obj(42); // using overload mechanism
}
您不应将标记的函数模板化,因为创建 ( ) 中使用的类型必须与调用 ( ) 中使用的类型完全make_shared
匹配。static_pointer_cast
或者,使用枚举:
#include <functional>
#include <string>
#include <iostream>
using std::string;
struct EG
{
enum stored_function_type
{
INT_FUNC, STRING_FUNC
};
union function_storage
{
std::function<void(int)> f_int;
std::function<void(string)> f_string;
function_storage()
: f_int()
{}
~function_storage()
{}
};
stored_function_type ft;
function_storage fs;
template < typename T > void destroy(T& p) { p.~T(); }
void destroy()
{
switch(ft)
{
case INT_FUNC:
destroy(fs.f_int);
break;
case STRING_FUNC:
destroy(fs.f_string);
break;
}
}
EG()
: ft(INT_FUNC)
{}
~EG()
{
destroy();
}
EG& operator=(std::function<void(int)>&& p)
{
destroy();
new(&fs.f_int) std::function<void(int)>( std::move(p) );
ft = INT_FUNC;
return *this;
}
EG& operator=(std::function<void(string)>&& p)
{
destroy();
new(&fs.f_string) std::function<void(string)>( std::move(p) );
ft = STRING_FUNC;
return *this;
}
void operator()(int p)
{
// better check ft == INT_FUNC
return fs.f_int(p);
}
void operator()(string p)
{
// better check ft == STRING_FUNC
return fs.f_string(p);
}
};
int main()
{
EG obj;
obj = [](int i) { std::cout << i; };
obj(42); // using overload mechanism
}
您可以使用花哨的模板元编程为许多类型简化此操作。
免责声明:我已经很久没有使用union
s.... 可能会错过一些东西。