如果这个例子比较复杂,我很抱歉,但我希望它能帮助人们更好地理解现代C++用法。所以我想让这段代码工作起来。它应该为单积分型和变分型产生特殊的lambdas,以便在硬静态转换为单积分型或软变分转换为普通型时计算项的顺序。我添加了注释,这些注释描述了我在这段代码中真正尝试做的事情。
#include <variant>
#include <type_traits>
#include <string>
#include <functional>
#include <iostream>
#include <memory>
#include <optional>
#include <any>
#include <utility>
/* Visitor */
// Should get values from a variant
template <class... Ts>
struct Visitor;
template <class T, class... Ts>
struct Visitor<T, Ts...> : T, Visitor<Ts...> {
Visitor(T t, Ts... rest) : T(t), Visitor<Ts...>(rest...) {}
using T::operator();
using Visitor<Ts...>::operator();
};
template <class T>
struct Visitor<T> : T {
Visitor(T t) : T(t) {}
using T::operator();
};
/* Calculator */
// Should get special lambda for same type integrals and for variant packed integrals
template<class T, class... Ts>
class Calculator {
public:
// lambda for simple calculate same type integrals
static auto sum = [](T a, T b) { return a + b; };
// api for get current value of variant
template<typename... Vs>
static auto variant_value(std::variant<Vs...> v) {
return std::visit(Visitor<Vs...>{}, v);
}
// lambda for unpack variant arguments calc common value and pack in variant again
template<typename... Vs>
static auto variant_sum = [](std::variant<Vs...> a, std::variant<Vs...> b) {
auto value = variant_value<Vs...>(a) + variant_value<Vs...>(b);
return std::variant<Vs...>(value);
};
};
/* Term Producer */
namespace term::legion {
using std::function, std::any;
template<typename T>
function<any(any)> legion(auto& algebra) noexcept { // std::function<T(T,T...)
function<any(any)> redex = [](std::any a) {return a;};
// I delete code here because its not important now
return redex;
}
// production lamda for single type values
template<typename T>
std::function<std::any(std::any)> sum(T arg) noexcept {
return legion<T>(Calculator<T>::sum);
};
// production lambda for variant type values
template<typename ...Vs>
std::function<std::any(std::any)> sum() noexcept {
std::cout << "variant sum selected" << std::endl;
return legion<std::variant<Vs...>>(Calculator<Vs...>::template variant_sum<Vs...>);
};
}
int main() {
// term contains lambda for single type
auto sm = term::legion::sum<int>();
// term contains lambda for variant type
auto v_sm = term::legion::sum<char, int16_t, double>();
}
我看不出有什么方法能让你的代码正常运行...
总之,有些问题/建议
>
也许您的访问者
可以工作,但您可以使用经典的方法:变量继承来更好地实现
模板
并避免专门化和递归
当你打电话的时候
自动sm=术语::军团::SUM();
在sum()
(假定vs...
是int
)中,
Calculator<int>::template variant_sum<int>
在variant_sum
(假定vs...
是int
)内部的调用,
variant_value<int>(a) + variant_value<int>(b);
在variant_value
(假定vs...
是int
)内实例化
Visitor<int>
问题是,visitor
继承自的是模板参数,类不能继承自int
。
要创建一个访问者,您需要与所有类型的变体一起工作的函数,但您必须稍微工作一些;例如,您可以编写一种操作符包装,如下所示
template <typename T>
struct foo
{ void operator() (T const &) { } };
和访问者如下
template <typename ... Ts>
struct Visitor : public foo<Ts>...
{ using foo<Ts>::operator()...; };
这样,visitor
从foo
继承(而不是从int
)和foo
作为接受int
的运算符()
。
这可以作为访客但你问
variant_value<Vs...>(a) + variant_value<Vs...>(b);
对于包含的值。
或者更好...从std::variant
(只有一个类型的变量)中,您可以。您可以修改foo
,如下所示
template <typename T>
struct foo
{ T operator() (T const & val) { return val; } };
还有(还有一些其他的修正)这个电话
auto sm = term::legion::sum<int>();
编译。
但是下面的sum()
auto v_sm = term::legion::sum<char, int16_t, double>();
因为结果的访问者(visitor
)包含三个不同的operator()
函数,返回三种不同的类型(char
、std::int16_t
和double
)。
但是std::visit()
必须返回一个类型。而不是根据变体中活动的类型而不同的类型。
所以我想你的代码应该重新考虑一下。