模板类:ctor对抗功能 - >新的C ++标准

时间:2010-05-08 14:09:23

标签: c++ templates function constructor

在这个问题中:
template; Point<2, double>; Point<3, double>
丹尼斯和迈克尔注意到了不合理的愚蠢实施的构造函数 他们是对的,我当时没有考虑到这一点。 但是我发现构造函数对像这样的模板类没有多大帮助,相反,函数在这里更加方便和安全

namespace point {

template < unsigned int dims, typename T >
struct Point {

    T X[ dims ];

    std::string str() {
        std::stringstream s;
        s << "{";
        for ( int i = 0; i < dims; ++i ) {
            s << " X" << i << ": " << X[ i ] << (( i < dims -1 )? " |": " ");
        }
        s  << "}";
        return s.str();
    }

    Point<dims, int> toint() {
        Point<dims, int> ret;
        std::copy( X, X+dims, ret.X );
        return ret;
    }
};

template < typename T >
Point< 2, T > Create( T X0, T X1 ) {
    Point< 2, T > ret;
    ret.X[ 0 ] = X0; ret.X[ 1 ] = X1;
    return ret;
}
template < typename T >
Point< 3, T > Create( T X0, T X1, T X2 ) {
    Point< 3, T > ret;
    ret.X[ 0 ] = X0; ret.X[ 1 ] = X1; ret.X[ 2 ] = X2;
    return ret;
}
template < typename T >
Point< 4, T > Create( T X0, T X1, T X2, T X3 ) {
    Point< 4, T > ret;
    ret.X[ 0 ] = X0; ret.X[ 1 ] = X1; ret.X[ 2 ] = X2; ret.X[ 3 ] = X3;
    return ret;
}
};
int main( void ) {
    using namespace point;
    Point< 2, double > p2d = point::Create( 12.3, 34.5 );
    Point< 3, double > p3d = point::Create( 12.3, 34.5, 56.7 );
    Point< 4, double > p4d = point::Create( 12.3, 34.5, 56.7, 78.9 );
    //Point< 3, double > p1d = point::Create( 12.3, 34.5 ); //no suitable user defined conversion exists

    //Point< 3, int > p1i = p4d.toint(); //no suitable user defined conversion exists
    Point< 2, int > p2i = p2d.toint();
    Point< 3, int > p3i = p3d.toint();
    Point< 4, int > p4i = p4d.toint();

    std::cout << p2d.str() << std::endl;
    std::cout << p3d.str() << std::endl;
    std::cout << p4d.str() << std::endl;
    std::cout << p2i.str() << std::endl;
    std::cout << p3i.str() << std::endl;
    std::cout << p4i.str() << std::endl;

    char c;
    std::cin >> c;
}  

新的C ++标准是否有关于模板类ctor的这方面的任何新改进,语言功能或简化?
您如何看待命名空间,stuct和Create函数组合的实现? 非常感谢提前 糟糕

2 个答案:

答案 0 :(得分:4)

由于数组是公共的,因此可以省略构造函数并允许聚合初始化(例如boost::array<T, N>)。

Point<2, int> p = {1, 2};

这并不比必须调用create函数更糟糕。 (创建函数可能仍然可以作为实用程序使用。)


在C ++ 0x中,你将能够拥有各种各样的酷感。例如,使用可变参数模板,如果使用正确数量的参数调用构造函数,则在编译时检查它。 (以下还可以检查参数...U是否都是T类型,还有一些元编程的乐趣,但它可能不是绝对必要的。)

//helper to copy variable amount of arguments into an array
namespace detail {

template <class T, class U>
void copy_variadic(T* p, U value)
{
    *p = value;
}

template <class T, class First, class ...Rest>
void copy_variadic(T* p, First var, Rest ...args)
{
    *p = var;
    copy_variadic(++p, args...);
}
} //detail

template < unsigned int dims, typename T >
struct Point {

    T X[ dims ];

    Point() : X{}
    {
    }

    template <class ...U>
    Point(U... args) {
        static_assert(sizeof...(args) == dims, "Too many or too few arguments to Point constructor");
        detail::copy_variadic(X, args...);
    }
    //...
};

(实际上,通过一些修改 - 完美转发 - copy_variadic会对我的可变参数模板实用程序集合做一个很好的补充,如果有人不来指出明显更好的方法。)

答案 1 :(得分:1)

是的,正如Michael在回答您之前的问题时指出的那样,在C ++ 0x中,您将能够使用初始化列表向您的ctor传递任意数量的参数。在您的情况下,代码看起来像:

template <int dims, class T>
class point { 
    T X[dims];
public:
    point(std::initializer_list<T> const &init) { 
        std::copy(init.begin(), init.begin()+dims, X);
    }
};

您可以使用以下内容创建一个点对象:

point<3, double> x{0.0, 0.0, 0.0};

就个人而言,我不确定我是否非常喜欢基本设计。特别是,我宁愿看到X变成std::vector,并严格从传递的参数列表中确定维度数,而不是将其作为模板参数:

template <class T>
class point { 
    std::vector<T> X;
public:
    point(std::initializer_list<T> init) {
        std::copy(init.begin(), init.end(), std::back_inserter(X));
    }
};

这确实有一些权衡 - 具有不同维数的点仍然是相同的类型。例如,它基本上断言将2D点分配给3D点是合理的,反之亦然。