可变参数模板是否可以与当前编译器一起正常工作?

时间:2014-03-21 13:36:28

标签: c++ c++11 g++ visual-studio-2013 mingw

我尝试根据c ++ 11变量模板功能实现一个简单的元组:

template <class Head, class... Tail>
class tuple;

template <class Head>
class tuple<Head>
{
public:
    tuple(Head h) : m_h( h ) {}

    tuple(tuple const & rhs)
    : m_h( rhs.m_h ) {}

    template<class T>
    tuple(tuple<T> const & rhs)
    : m_h( rhs.head() )
    {}

    Head head() const
    {
        return m_h;
    }
private:
    Head m_h;
};

template <class Head, class... Tail>
class tuple : private tuple<Tail...>
{
public:
    typedef tuple<Tail...> inherited;
    tuple(Head h, Tail... tail)
    : inherited(tail...), m_h( h )
    {}

    Head head() const
    {
        return m_h;
    }

    inherited &
    tail()
    {
        return *this;
    }

    inherited const &
    tail() const
    {
        return *this;
    }

    template<typename... Values>
    tuple(tuple<Values...> const & rhs)
    : inherited( rhs.tail() ),
      m_h( rhs.head() )
167:    {}
private:
    Head m_h;
};

并试图按如下方式使用它:

    tuple<int, double, char> tpl(0, 3.3, 'a');
175:    tuple<long, float, short> tpl2 = tpl;

这导致:

test.cpp(167) : error C2664: 'tuple<short,>::tuple(const tuple<short,> &)' : can not convert argument 1 from 'const tuple<char,>' to 'short'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
test.cpp(167) : see reference to function template instantiation 'tuple<float,short>::tuple<double,char>(const tuple<double,char> &)' being compiled
test.cpp(167) : see reference to function template instantiation 'tuple<float,short>::tuple<double,char>(const tuple<double,char> &)' being compiled
test.cpp(175) : see reference to function template instantiation 'tuple<long,float,short>::tuple<int,double,char>(const tuple<int,double,char> &)' being compiled
test.cpp(175) : see reference to function template instantiation 'tuple<long,float,short>::tuple<int,double,char>(const tuple<int,double,char> &)' being compiled

使用Visual Studio 2013并在:

c:\Users\achernyaev\Documents\test.cpp: In function 'int main()':
c:\Users\achernyaev\Documents\test.cpp:175:35: error: conversion from 'tuple<int,double, char>' to non-scalar type 'tuple<long int, float, short int>' requested tuple<long,float,short> tpl2 = tpl;
                              ^

使用MinGW的g ++ 4.8.1

问题:此代码是否真的格式错误,或者此功能可能不够支持?

最好的问候,亚历山大。

2 个答案:

答案 0 :(得分:2)

代码中有几个错误:这是一个更正的错误:

template <class ...> class tuple; // declaration as a multivariate template.

template <class Head>
class tuple<Head>
{
private:
    Head m_h; 
public:
    tuple(Head h) : m_h( h ) {}

    tuple(tuple const & rhs)
    : m_h( rhs.m_h ) {}

    template<class T>
    tuple(tuple<T> const & rhs)
    : m_h( rhs.head() )
    {}

    Head head() const
    {
        return m_h;
    }
};

template <class Head, class... Tail>
class tuple<Head, Tail...> : // explicitly write the partial specialization. 
   private tuple<Tail...> 
{
private:
    Head m_h;

    typedef tuple<Tail...> inherited;
    tuple(Head h, Tail... tail)
    : inherited(tail...), m_h( h )
    {}

    Head head() const
    {
        return m_h;
    }

    inherited &
    tail()
    {
        return *this;
    }

    inherited const &
    tail() const
    {
        return *this;
    }

    template<typename... Values>
    tuple(tuple<Values...> const & rhs)
    : inherited( rhs.tail() ),
      m_h( rhs.head() )    {}
};

答案 1 :(得分:0)

您的转换构造函数的扣除失败:

template<typename... Values>
tuple(tuple<Values...> const & rhs)
: inherited( rhs.tail() ),
  m_h( rhs.head() )
{}

但在定义为:

时成功
template<typename H, typename... T>
tuple(tuple<H, T...> const & rhs)
: inherited( rhs.tail() ),
  m_h( rhs.head() )
{}

我认为在尝试将参数包ValuesHead模板的非包参数tuple匹配时,扣除失败,符合C ++11§14.8.2.5[ temp.deduct.type] / 10:

  

如果对应于P i 的参数声明是函数参数包,则将其declarator-id的类型与A的参数类型列表中的每个剩余参数类型进行比较。每个比较都推导出函数参数包扩展的模板参数包中后续位置的模板参数。在部分排序(14.8.2.4)期间,如果A i 最初是函数参数包:

     
      
  • 如果P不包含对应于A i 的函数参数类型,则忽略A i ;

  •   
  • 否则,如果P i 不是函数参数包,则模板参数推断失败。

  •   

在任何情况下,您都可以通过将空元组作为递归的基本案例并将整个shebang定义为:

来简化类。
template <class...> class tuple {};

template <class Head, class... Tail>
class tuple<Head, Tail...> : private tuple<Tail...>
{
public:
    typedef tuple<Tail...> inherited;

    tuple(Head h, Tail... tail)
    : inherited(tail...), m_h( h )
    {}

    Head head() const
    {
        return m_h;
    }

    inherited &
    tail()
    {
        return *this;
    }

    inherited const &
    tail() const
    {
        return *this;
    }

    template<typename... T>
    tuple(tuple<T...> const & rhs)
    : inherited( rhs.tail() ),
      m_h( rhs.head() )
    {}

private:
    Head m_h;
};