假设我有一个模板类,如下所示:
template<class T, class V>
class MyClass
{
public:
MyClass(std::string const& name){
s = name;
}
T return_var1() {
return var1;
}
std::string s;
T var1;
V var2;
};
我将如图所示使用它:
class AnotherClass {
public:
void some_func() {
MyClass<int, double> my_var("test");
std::pair<std::string, std::any> tmp_pair("test", my_var);
my_vars.insert(tmp_pair);
}
void some_other_func() {
auto tmp = my_vars["test"];
// Any way to call member function without using std::any_cast<...> ?
// For example, not like this:
// (std::any_cast<MyClass<int, double>>tmp).return_var1()
// But like this:
std::cout << tmp.return_var1();
}
private:
std::unordered_map<std::string, std::any> my_vars;
}
有没有办法在不知道或不使用所包含对象的类型的情况下调用存储在 std::any 中的对象的成员函数? (不使用上面评论中所写的 std::any_cast<>() )
任何解决方案都是可以接受的,例如使用 CRTP 从基类继承 MyClass,使用
std::variant
等等。
我需要这个的原因是因为我想使用这样的模板化函数:
some_templated_function<decltype(my_var.var1)>();
// Or similarly,
some_templated_function<decltype(my_var.return_var1())>();
目的是允许用户仅注册类型
<int, double>
一次,并在需要时广泛使用类型名称。
是的,只要应该调用的函数具有已知的签名,这是可能的。我将使用一个更简单的例子来描述事情,就像你的OP中的例子一样。假设您有两个类提供具有固定签名的成员函数
greet
:
struct A
{
void greet() const { std::cout<< "hello" << std::endl; }
};
struct B
{
void greet() const { std::cout<< "goodbye" << std::endl; }
};
使用
std::any
,您可以包装这些类的任何实例:
std::any a = A();
a = B();
但是,为了使用包含的对象,您始终必须知道当前包含的确切类型。如果您有许多类型或者这些类型不是您自己定义的(例如在库中),则这是不幸的。以下代码给出了克服此要求的基本方法:
struct any_caller
{
template<typename T>
any_caller(T object)
: any_(object)
, greet_([](std::any const& a){ return std::any_cast<T const&>(a).greet();})
{}
std::any any_;
void (*greet_)(std::any const&);
auto greet() const { return greet_(any_); }
};
想法如下:
std::any
的对象的类型。您可以使用此信息来设置执行 std::any_cast
的 lambda,然后调用所需的函数。上面的代码可以按如下方式使用:
int main()
{
any_caller c = A();
c.greet(); //prints "hello"
c = B();
c.greet(); //prints "goodbye"
}