Использование auto с переменными шаблонами, которые генерируют кортеж - PullRequest
0 голосов
/ 21 июня 2019

Я работал над этим в течение некоторого времени, и нашел это Q / A как хороший ответ о том, как я могу хранить кортеж.Теперь я пытаюсь использовать шаблон функции, который сгенерирует этот класс, и ключевое слово auto для создания экземпляров этого объекта.Я не получаю никаких ошибок компилятора;пока он не генерирует никаких данных, и я не могу понять, где я ошибаюсь, однако, мой ostream<<() генерирует ошибки компилятора с жалобами на std::get

Вот мой класс и несколько способово том, как я пытаюсь его использовать.

#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;
}



Редактировать

Я воспользовался советом Игоря и попытался использовать cppreference'sнайденный пример здесь и это то, что я придумал для моего 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';
}

Это жалуется на то, что Is необходимо расширить, хорошо, поэтому я пытаюсь расширитьэто в функции print..., и я попытался поместить оператор ... в нескольких местах, и, похоже, ничего не компилируется.Я не уверен, как расширить Is в этом контексте, или я могу даже использовать выражения свертки.

1 Ответ

2 голосов
/ 21 июня 2019

Как уже упоминалось в комментариях, нетипичные параметры шаблона требуют константных выражений во время компиляции.Вот почему std::get нельзя использовать так, как вы.

Если вы хотите перебрать элементы кортежа, я бы рекомендовал использовать std::apply, который специально разработансделать это.Возможная повторная реализация вашего фрагмента кода:

#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;
}
...