将auto与生成元组的可变参数模板一起使用 [英] Using auto with variadic templates that generates a tuple

查看:115
本文介绍了将auto与生成元组的可变参数模板一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经为此工作了一段时间,并且发现了问题/解答,很好地回答了我可以存储一个元组。现在,我尝试使用将生成此类和自动关键字的函数模板来生成该对象的实例。我没有收到任何编译器错误;但是它没有生成任何数据,我无法弄清楚哪里出了问题,但是,我的 ostream<<<()正在生成编译器错误,抱怨 std :: get

I have been working on this for some time and I found this Q/A as a good answer into how I can store a tuple. Now I'm trying to use a function template that will generate this class and the auto key word to generate instances of this object. I'm not getting any compiler errors; yet it isn't generating any data and I can not figure out where I'm going wrong, however, my ostream<<() is generating compiler errors complaining about std::get

这是我的课程,以及一些尝试使用它的方法。 / p>

Here is my class and a few ways of how I'm trying to use it.

#include <algorithm>
#include <iostream>
#include <tuple>

template<class... T>
class expression_t {
public:
    std::tuple<T...> rhs;
    std::size_t size = sizeof...(T);        

    template<class... Args>
    expression_t(Args&& ...args) : rhs( std::forward<Args>(args)... ){}    
    std::tuple<T...> operator()() {
        return hrs;
    }
};

template<typename... Args>
expression_t<Args...> expression(Args... args) {
    expression_t<Args...> expr(args...);
    return expr;
}

template<typename... Args>
std::ostream& operator<< (std::ostream& os, const expression_t<Args...>& expr) {            

    for (std::size_t n = 0; n < expr.size; n++ ) {
        if ( std::get<n>(expr.rhs) == '+' || std::get<n>(expr.rhs) == '-' || 
             std::get<n>(expr.rhs) == '*' || std::get<n>(expr.rhs) == '/' || 
             std::get<n>(expr.rhs) == '%')
             os << ' ' << std::get<n>(expr.rhs) << ' ';
        os << std::get<n>(expr.rhs);
    }
    os << '\n';

    return os;
}

int main() {
    double x = 0;
    // example: 4x^2 + 2x
    auto expr = expression( 4, x, '^', 2, '+', 2, x );

    // try to print a single element from expr's tuple member
    auto t = expr(); // using operator()        
    std::cout << std::get<2>(t); // compiles and runs but does not work

    // try to print out the expression
    std::cout << expr; // the ostream<<() operator fails to compile
    // it is complaining about `std::get` with no matching overloaded function found 
    // with MSVC error C2672

    return 0;
}




编辑

我接受了Igor的建议,并尝试使用cppreference的示例找到这里,这就是我为 operator<<<()

I took Igor's advice and tried to use cppreference's example found here and this is what I have come up with for my operator<<().

template<class Ch, class Tr, class Tuple, std::size_t... Is>
void print_expression_tuple_impl(std::basic_ostream<Ch, Tr>& os, const Tuple& t, std::index_sequence<Is...>) {
    if ( (std::get<Is>(t) == '+') || 
         (std::get<Is>(t) == '-') ||
         (std::get<Is>(t) == '*') || 
         (std::get<Is>(t) == '/') ||
         (std::get<Is>(t) == '%') )
        os << " " << std::get<Is>(t) << " ";
    os << std::get<Is>(t);
}

template<class Ch, class Tr, class... Args>
auto& operator<<(std::basic_ostream<Ch,Tr>& os, const std::tuple<Args...>& t) {         
    print_expression_tuple_impl(os, t, std::index_sequence_for<Args...>{});
    return os;
}

template<class... Args>
std::ostream& operator<<(std::ostream& os, const expression_t<Args...>& expr) {
    return os << expr.rhs << '\n';
}

这抱怨需要扩展,好吧,所以我尝试在 print ... 函数中扩展它,并尝试放置 ... 运算符在多个位置,似乎没有任何编译。我不确定在这种情况下如何扩展,或者我什至可以使用折叠表达式。

This complains that Is needs to be expanded, okay so I try to expand it in the print... function and I've tried placing the ... operator in multiple places and nothing seems to compile. I'm not sure how to expand Is in this context, or if I can even use fold expressions.

推荐答案

如注释中所述,非类型模板参数需要编译时常量表达式。这就是为什么 std :: get 不能像以前那样使用的原因。

As mentioned in the comments, non-type template parameters need compile-time constant expressions. That’s why std::get cannot be used the way you did.

如果要遍历元素元组,我建议使用 std :: apply ,这是专门为此设计的。
您可能会被重新实现的代码被重新实现:

If you want to iterate over the elements of a tuple, I would recommend to use std::apply, which is specifically designed to do so. A possible reimplementation of your code snipped would be:

#include <algorithm>
#include <iostream>
#include <tuple>

template<class... T>
class expression_t {
public:
    std::tuple<T...> rhs;
    std::size_t size = sizeof...(T);        

    template<class... Args>
    expression_t(Args&& ...args) : rhs( std::forward<Args>(args)... ){}    

    std::tuple<T...> operator()() const { // Needs to be const to be used by the operator <<
        return rhs;
    }
};

template <typename T>
void Print(std::ostream& os, T x) {
    os << x;
}

template <>
void Print<char>(std::ostream& os, char x) {
if ( x == '+' || x == '-' ||  x == '*' || x == '/' || x == '%')
  os << ' ' << x << ' ';
}

template<typename... Args>
expression_t<Args...> expression(Args... args) {
    expression_t<Args...> expr(args...);
    return expr;
}

template<typename... Args>
std::ostream& operator <<(std::ostream& os, const expression_t<Args...>& expr) {            

    auto Fn = [&os](auto... x) {
      (Print(os, x), ...);                 // Fold over a comma
    };

    std::apply(Fn, expr());

    os << '\n';

    return os;
}


int main() {
    double x = 0;
    // example: 4x^2 + 2x
    auto expr = expression( 4, x, '^', 2, '+', 2, x );

    auto t = expr();
    std::cout << std::get<2>(t) << '\n'; // Prints ^ as expected

    std::cout << expr;

    return 0;
}

这篇关于将auto与生成元组的可变参数模板一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆