- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
class EG
{
template<class T>
std::function<void(T)> f;
//these are supposed to be appropriate instantiations that I have to look up how to do as I haven't really used templates
template<std::string> f;
template<int> f;
template<class T>
void func(std::function<void(T)>&& arg)
{
f<std::string> = nullptr;
f<int> = nullptr;
f.swap(arg);
}
};
这是我要做的。
EG eg;
eg.func([](std::string s){});
eg.func([](int i){});
有一个回调缓存 (f),它可以接受不同的参数(指向对象的指针、位置 vector 等)。它用于模拟程序中的鼠标定位。当我开始另一个目标进程时,我需要取消当前目标(这意味着现在 f = null)。我只是不想要很多实际上做同样事情的函数和成员(但对于不同的参数)。我该如何解决这个问题?
我可以简单地检查是否有一个带有 bool 而不是 f == null 的目标,但我仍然需要多个 f 实例用于不同的回调参数)。使用 bool 而不是 f == nullptr 检查将阻止我拥有模板化类。检查 f == nullptr 是否也会阻止我拥有模板化类。
更多案例信息:
这实际上是一个回调处理程序,T 只有两种不同的类型在使用(当前)。
我试图防止它们有多个 f1、f2... 和 void func 变体。
最佳答案
评论有点长,所以我将其作为答案发布:
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)
通过 obj.func
,它应该接受一个 int;如果你分配一个 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 以来已经有很长一段时间了……可能会遗漏一些东西。
关于c++ - 模板类成员?由于没有任何行为,如何适本地实现这种行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16571818/
我是一名优秀的程序员,十分优秀!