当前位置: 首页 > 知识库问答 >
问题:

带有variadic模板的Variant

石超
2023-03-14

如果这个例子比较复杂,我很抱歉,但我希望它能帮助人们更好地理解现代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>();
}

共有1个答案

漆雕伟志
2023-03-14

我看不出有什么方法能让你的代码正常运行...

总之,有些问题/建议

>

  • 也许您的访问者可以工作,但您可以使用经典的方法:变量继承来更好地实现

    模板 结构访问者:公共TS...{使用ts::运算符()...;};

    并避免专门化和递归

    当你打电话的时候

    自动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 (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 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()函数,返回三种不同的类型(charstd::int16_tdouble)。

    但是std::visit()必须返回一个类型。而不是根据变体中活动的类型而不同的类型。

    所以我想你的代码应该重新考虑一下。

  •  类似资料:
    • 我知道接受参数和,所以我已经尝试了2次(失败)来包装函数和args...: a.创建一个C样式的函数,该函数将调用传递给它的对象: 这会在GCC 4.8.5中导致以下错误: /usr/include/c++/4.8.2/functional:在'struct std::_bind_simple(std::_placeholder<1>,int))(int*)>>()>'的实例化中:/usr/inc

    • 要解决的问题: 怎么创建一个拥有1个、2个或者更多的初始化器的类? 怎么避免创建一个实例而只拷贝部分的结果? 怎么创建一个元组? 最后的问题是关键所在:考虑一下元组!如果你能创建并且访问一般的元组,那么剩下的问题也将迎刃而解。 这里有一个例子(摘自“可变参数模板简述(A brief introduction to Variadic templates)”(参见参考)),要构建一个广义的、类型安全的

    • 我学习了一些关于variadic模板的知识,并在Internet上搜索了一些示例,现在尝试编写一些棘手的代码来调用member一个variadic类模板的方法,其中包含一个字段。我不明白为什么它不起作用。拜托,救命。 以下是示例类: 和来自Main的呼叫: 错误: main.cpp 1>d:\drafts_tests\main.cpp(203):错误C2198:“void(__thiscall f

    • 问题内容: 我希望能够一次定义模板,并使用它们从服务器端和客户端渲染HTML。(DRY原则及其他) 我正在设想的API就是这样:render(JSON,template)-> html。 我正在使用Java框架(实际上是Play框架,但是我不认为这是特定于框架的)。 我几乎同意作者的观点,显而易见的竞争者如:Mustache和Google Closure Templates不会削减它。(出于原因请

    • 我有个奇怪的问题。我有1个ARM模板,我用它部署2个环境。 删除完整的QA资源组后,我能够重新部署完全相同的ARM模板。看来资源组应该创建后的密钥库秘密?知道为什么吗?如果我们在生产中遇到这种情况,我们不希望删除完整的资源组

    • 当我的模板包含一些JavaScript时,我遇到了一个问题。例如: 果然,模板解释器希望将双卷曲大括号{{}}中的所有内容解释为变量。现在我想知道是否有办法关闭类似于的此类行为。