0

对不起,如果这个案例相当复杂,但我希望它可以帮助人们更好地理解现代 c++ 的用法。所以我想让这段代码工作。它应该为单个整数类型和变体类型生成特殊的 lambda,用于计算硬静态转换为单一类型或软变体转换为通用类型的术语序列,而这些术语将被使用。我添加了描述我在这段代码中真正尝试做的事情的注释。

#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>();
}
4

1 回答 1

1

我看不到使您的代码有效的方法...

无论如何,一些问题/建议

  1. 也许你的Visitor作品,但你可以使用经典的方式做得更好:可变参数继承
template <typename ... Ts>
struct Visitor : public Ts...
 { using Ts::operator()...; };

并避免专业化和递归

  1. 你打电话时
auto sm = term::legion::sum<int>();

你有,里面sum()(假设Vs...int),

Calculator<int>::template variant_sum<int>

那个调用,在里面variant_sum(假设Vs...int),

variant_value<int>(a) + variant_value<int>(b);

实例化,内部variant_value<int>(a)(假设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<int>继承自foo<int>(而不是继承自int)并foo<int>作为operator()接受一个int.

这可以作为访客,但你问

variant_value<Vs...>(a) + variant_value<Vs...>(b);

为包含的值。

  1. 大问题来了:你不能从std::visit.

或者更好......从std::variant<int>(只有一个类型的变体),你可以。你可以修改foo<T>如下

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<char, std::int16_t, double>) 包含三个不同的operator()函数,返回三种不同的类型 (charstd::int16_t) double

std::visit()必须返回单一类型。根据变体中活动的类型,没有不同的类型。

所以我想你的代码必须完全重新考虑。

其他小问题

  1. 以下声明在 C++20 中是好的
template<typename T>
function<any(any)> legion(auto& algebra) noexcept

但在 C++17 中,不能auto用作参数类型的占位符(通用 lambda 除外);正确的 C++17 方式通过一个额外的模板参数,所以

template <typename T, typename U>
function<std::any(std::any)> legion (U & algebra) noexcept
  1. 添加constexprforsumvariant_suminsideCalculator
static constexpr auto sum = ...

static constexpr auto variant_sum = ...
  1. 如果Calculator只有public成员,则将其设为struct.
于 2021-04-07T15:28:31.163 回答