如何使用具有运行时类型的编译时接口?
How to use a compile-time interface with a runtime type?
我有一个函数接受 T
并在提供的对象上调用特定函数。直到现在它都是在编译时对象中使用的,所以一切都很好。最小示例:
#include <iostream>
struct A {
void fun() const { std::cout << "A" << std::endl; }
};
struct B {
void fun() const { std::cout << "B" << std::endl; }
};
template<class T>
void use_function(const T& param) {
param.fun();
}
int main() {
use_function(A{}); // "A"
use_function(B{}); // "B"
return 0;
}
现在,我正尝试将 use_function()
用于运行时创建的对象,但遇到了困难。我不能使用 std::variant
或 std::any
,因为我需要为它们的访问函数提供类型作为模板参数——尽管 all 它们的变体实现了函数接口。 (失败的)变体方法示例:
using var_type = std::variant<A, B>;
struct IdentityVisitor {
template<class T>
auto operator()(const T& alternative) const -> T {
return alternative;
}
};
int main() {
var_type var = A{};
// error C2338: visit() requires the result of all potential invocations to have the same type and value category (N4828 [variant.visit]/2).
use_function(std::visit(IdentityVisitor{}, var));
return 0;
}
是可能的是直接调用具有适当类型的函数,如下所示:
if (rand() % 2 == 0)
use_function(A{});
else
use_function(B{});
只是将它存储在两者之间是我无法工作的。
我在技术层面上理解,但很难想出一个优雅的解决方案。有吗?我知道我可以用轻量级继承来重写对象——但我试图看看完全避免它是否可行,即使只是作为一个练习来避免 OOP 而支持模板和概念。我 感觉 喜欢的变体应该与此一起使用,但显然不是。
std::visit([](auto const& x) { use_function(x); }, var);
如果重载集是对象,您可以将 use_function
直接传递给 std::visit
。因为它们不是,所以您需要将其包装在将实例化为对正确重载的调用的内容中。
std::visit([](auto const& x) { use_function(x); }, var);
我有一个函数接受 T
并在提供的对象上调用特定函数。直到现在它都是在编译时对象中使用的,所以一切都很好。最小示例:
#include <iostream>
struct A {
void fun() const { std::cout << "A" << std::endl; }
};
struct B {
void fun() const { std::cout << "B" << std::endl; }
};
template<class T>
void use_function(const T& param) {
param.fun();
}
int main() {
use_function(A{}); // "A"
use_function(B{}); // "B"
return 0;
}
现在,我正尝试将 use_function()
用于运行时创建的对象,但遇到了困难。我不能使用 std::variant
或 std::any
,因为我需要为它们的访问函数提供类型作为模板参数——尽管 all 它们的变体实现了函数接口。 (失败的)变体方法示例:
using var_type = std::variant<A, B>;
struct IdentityVisitor {
template<class T>
auto operator()(const T& alternative) const -> T {
return alternative;
}
};
int main() {
var_type var = A{};
// error C2338: visit() requires the result of all potential invocations to have the same type and value category (N4828 [variant.visit]/2).
use_function(std::visit(IdentityVisitor{}, var));
return 0;
}
是可能的是直接调用具有适当类型的函数,如下所示:
if (rand() % 2 == 0)
use_function(A{});
else
use_function(B{});
只是将它存储在两者之间是我无法工作的。
我在技术层面上理解,但很难想出一个优雅的解决方案。有吗?我知道我可以用轻量级继承来重写对象——但我试图看看完全避免它是否可行,即使只是作为一个练习来避免 OOP 而支持模板和概念。我 感觉 喜欢的变体应该与此一起使用,但显然不是。
std::visit([](auto const& x) { use_function(x); }, var);
如果重载集是对象,您可以将 use_function
直接传递给 std::visit
。因为它们不是,所以您需要将其包装在将实例化为对正确重载的调用的内容中。
std::visit([](auto const& x) { use_function(x); }, var);