2015-02-15 2 views
8

Прошло некоторое время, когда я делал C++, но я не знаком с шаблонами.Итерация на кортеже ... снова

Недавно я попытался написать класс, который обертывает std::vector<std::tuple<Types...>>. Этот класс должен иметь функции-члены, и мне действительно нужно иметь возможность перебирать над кортежем. На самом деле, если я могу печатать каждый элемент кортежа (в порядке), я мог бы делать все, что мне нужно.

Я нашел решение с использованием приведения, но я не уверен в этом, так как он основан на актере, который мне не очень нравится (плюс, когда я пытаюсь использовать static_cast, он не компилируется больше).

Мой вопрос в том, является ли следующий код правильным, портативным, является ли это взломом, и должен ли я найти другой способ сделать это, чем использовать этот листинг? Кроме того, этот актер, вероятно, прав на исполнение во время выполнения? Есть ли способ сделать то, что я хочу без этого?

std::ostream& operator<<(std::ostream& out, std::tuple<> const& tuple) 
{ 
    return out; // Nothing to do here 
} 

template<typename First, typename... Types> 
std::ostream& operator<<(std::ostream& out, std::tuple<First, Types...> const& tuple) 
{ 
    out << std::get<0>(tuple) << " "; 

    // The cast that I don't like 
    return out << (std::tuple<Types...>&) tuple; 
} 

int main() 
{ 
    auto tuple = std::make_tuple(1, 2.3, "Hello"); 
    std::cout << tuple << std::endl; 
    return 0; 
} 

Заранее благодарю вас за ответы.

+0

Этот тип выглядит как 'reinterpret_cast'. Так что нет, не хорошо. – 0x499602D2

+1

Это даже [производит segfault] (http://coliru.stacked-crooked.com/a/9f96f1e786b070f1) при использовании clang ++ и libC++ – dyp

+0

@dyp Это именно то, что я хотел знать, спасибо! – tforgione

ответ

10

std::index_sequence_for для удовольствия и использования.

template <typename TupleLike, size_t ... Inds> 
std::ostream& PrintHelper(std::ostream& out, TupleLike const& tuple, std::index_sequence<Inds...>) 
{ 
    int unused[] = {0, (void(out << std::get<Inds>(tuple) << " "), 0)...}; 
    (void)unused; 
    return out; 
} 

template<typename... Types> 
std::ostream& operator<<(std::ostream& out, std::tuple<Types...> const& tuple) 
{ 
    return PrintHelper(out, tuple, std::index_sequence_for<Types...>()); 
} 

EDIT: Live Demo. Благодаря @dyp. Это использует трюк расширения от this answer.

+0

Обратите внимание, что это вызывает повреждение стека в MSVC, но эквивалент, используемый с помощью 'std :: array <>', отлично работает. – ildjarn

+1

VC++ 2015 исправил проблему с повреждением стека. – ildjarn

0

Я нашел другой способ сделать то, что хочу. Я использовал this article, который может печатать элементы кортежа в порядке убывания, и я использую второй индекс J == std::tuple_size<std::tuple<Types...>>::value - I, поэтому я могу специализировать шаблон при I==0.

template<std::size_t I, std::size_t J, typename... Types> 
struct printHelper 
{ 
    std::ostream& operator()(std::ostream& out, std::tuple<Types...> const& tuple) 
    { 
     out << std::get<J>(tuple) << " "; 

     // Recursive call without cast 
     return printHelper<I-1,J+1,Types...>{}(out, tuple); 
    }; 
}; 

// Specialization on the last element when I==0 
template<std::size_t J, typename... Types> 
struct printHelper<0,J,Types...> 
{ 
    std::ostream& operator()(std::ostream& out, std::tuple<Types...> const& tuple) 
    { 
     // Nothing to do here 
     return out; 
    } 
}; 

template<typename... Types> 
std::ostream& operator<<(std::ostream& out, std::tuple<Types...> const& tuple) 
{ 
    return printHelper<std::tuple_size<std::tuple<Types...>>::value, 0, Types...>{}(out, tuple); 
} 
Смежные вопросы