samedi 27 août 2016

How to form a variadic template function within a non-variadic template class?

So, as I've been learning about templates in C++, I decided to come up with some unusual situations to see if I could get them to work. (No, it's not practical - just to play with the language!) I made a template class that holds a value of type T, with a variadic function template that returns a std::pair of T and the maximum of one of the values in the parameter pack. However, I can't get it to compile. Here's what I wrote...

In header.h:

#ifndef HEADER_H
#define HEADER_H

#include <utility>
#include <algorithm>
#include <array>

template <typename  T>
class MyClass
{

  T m_heldType;

public:

  MyClass(T t) : m_heldType(t) {}

  template <typename... T2>
  std::pair<T, T2> pairingFunc(T2&&... types)
  {
    std::array<T2, sizeof...(types)> types_arr = { types... };

    return std::make_pair( m_heldType, *std::max_element(types_arr.begin(), types_arr.end()) );
  }

};

#endif

In source.cpp:

#include <iostream>
#include "Header.h"

int main()
{
  MyClass<int> mc(512);

  auto mypair = mc.pairingFunc(1.61f, 3.14f, 6.66f);

  std::cout << mypair.first << ' ' << mypair.second;
  std::cin.ignore();
}

These are the errors I generate:

Error   C3520   'T2': parameter pack must be expanded in this context   ...\header.h    24
Error   C2672   'MyClass<int>::pairingFunc': no matching overloaded function found  ...\source.cpp  8
Error   C2893   Failed to specialize function template 'std::pair<T,T2> MyClass<T>::pairingFunc(T2 &&...)'  ...\source.cpp  8
Error   C3536   'mypair': cannot be used before it is initialized   ...\source.cpp  10
Error   C2228   left of '.first' must have class/struct/union   ...\source.cpp  10
Error   C2228   left of '.second' must have class/struct/union  ...\source.cpp  10

So here's what I'm thinking:

  • Obviously, the compiler can't determine the type of mypair (fails to initialize). But why? It knows the type of T in MyClass and the type of T2 in pairingFunc(). Explicitly stating std::pair<int, float> fixes this error, but leaves the others (a symptom of the underlying issue).
  • "Failed to specialize function template"...which I guess means that it couldn't return the type based on the types given? If so, why not?
  • "parameter pack must be expanded in this context" - I'm not sure about this one. Doesn't that occur by putting the pack into an array?

Additionally, I'd like to enforce provision of at least one argument through something like (T2&& head, T2&&... tail), but I think getting both of those into an array or vector could be nasty, and I'm not sure how to deal with just the single variadic as it is. So that's just a 'bonus' I guess.

Aucun commentaire:

Enregistrer un commentaire