首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模板;Point<2,double>;Point<3,double>

模板;Point<2,double>;Point<3,double>
EN

Stack Overflow用户
提问于 2010-05-06 15:08:10
回答 6查看 2.3K关注 0票数 0

我想创建我自己的Point struct,它只是为了学习C++。

我有以下代码:

代码语言:javascript
复制
template <int dims, typename T>
struct Point {
    T X[dims];
    Point(){}
    Point( T X0, T X1 ) {
        X[0] = X0;
        X[1] = X1;
    }
    Point( T X0, T X1, T X2 ) {
        X[0] = X0;
        X[1] = X1;
        X[2] = X2;
    }
    Point<dims, int> toint() {
        //how to distinguish between 2D and 3D ???
        Point<dims, int> ret = Point<dims, int>( (int)X[0], (int)X[1]);
        return ret;
    }
    std::string str(){
        //how to distinguish between 2D and 3D ???
        std::stringstream s;
        s << "{ X0: " << X[0] << " | X1: " <<  X[1] << " }";
        return s.str();
    }
};
int main(void) {

    Point<2, double> p2d = Point<2, double>( 12.3, 45.6 );
    Point<3, double> p3d = Point<3, double>( 12.3, 45.6, 78.9 );

    Point<2, int> p2i = p2d.toint(); //OK
    Point<3, int> p3i = p3d.toint(); //m???

    std::cout << p2d.str() << std::endl; //OK
    std::cout << p3d.str() << std::endl; //m???
    std::cout << p2i.str() << std::endl; //m???
    std::cout << p3i.str() << std::endl; //m???

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

当然,到目前为止,输出结果并不是我想要的。我的问题是:在Point的成员函数中,如何处理Point的尺寸(2D或3D)?

非常感谢你提前

哦哦

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2010-05-06 15:15:20

你的维度在编译时是固定的,通过模板arguemnt dims,所以你可以遍历它们:

代码语言:javascript
复制
std::string str(){
    //how to distinguish between 2D and 3D ???
    std::stringstream s;
    s << "{ ";
    std::copy( X, X+dims, std::ostream_iterator<T>( s, "|") );
    s << " }";
    return s.str();    
}

此外,您还可以根据dims提供构造函数

代码语言:javascript
复制
Point( const T (&c) [dims] ){
  std::copy( c, c+dims, X );
}

这允许像double[] d={1,2,3}; Point<3,double> p(d);这样的代码,它将决定其他地方的参数数量。

对于‘cast-to-point-of-int’构造函数,你可以使用Point作为参数:

代码语言:javascript
复制
Point<dims,int> toint() const {
    Point<dims,int> result;
    std::copy( X, X+dims, result.X );
    return result;
}
票数 6
EN

Stack Overflow用户

发布于 2010-05-06 15:20:06

您应该简单地使用循环,而不是硬编码赋值。例如:

代码语言:javascript
复制
std::string str(){
    if ( dims > 0 ){
        std::stringstream s;
        s << "{ X0: " << X[0];
        for ( int i = 1; i < dims; i++ ){
            s << " | X" << i << ": " <<  X[i];
        }
        s <<" }";
        return s.str();
    }
    return "{}";
}

但是,就构造函数而言,您必须专门化模板以使其具有正确数量的参数,或者必须等待C++0x使用初始化器列表,或者只能满足于一种功能稍弱的语法,在这种语法中传入一个初始化数组。但是,对于所有其他函数,您可以只使用一个For循环,使用dims来确定点的尺寸。我还应该指出,boost::array类可能已经提供了您需要的功能,如果没有,建议在该类的基础上构建您需要的任何功能,因为它与您所拥有的非常相似。

另外,您应该为您的类提供一个典型的ostream str函数,并且可以选择在此函数之上实现operator<< ()函数,因为您已经在您的str()实现中有效地实现了它,但是提供操作符重载比简单地提供str()更加灵活和强大。您也可能对boost::lexical_cast感兴趣,因为它可以将任何提供ostream操作符的对象字符串化为字符串。

票数 3
EN

Stack Overflow用户

发布于 2010-05-06 17:45:57

正如其他人所说,只需使用dims作为变量即可回答how to distinguish between 2D and 3D?

更有趣的问题是如何让构造器的行为使得你只能调用正确的构造器。一种替代方法是boost::enable_if,如果条件不满足,它会生成一个有目的的编译器错误,从本质上取消函数声明。

代码语言:javascript
复制
template <int dims, typename T>
struct Point {
    T X[dims];
    Point(){} // should this really be empty?
    Point( typename enable_if_c< dims == 2, T >::type X0, T X1 ) {
        X[0] = X0;
        X[1] = X1;
    }
    Point( typename enable_if_c< dims == 3, T >::type X0, T X1, T X2 ) {
        X[0] = X0;
        X[1] = X1;
        X[2] = X2;
    }

这种技术通常被称为SFINAE,因为替换失败并不是一个错误(潜台词:编译器可能会尝试另一个重载),但在这种情况下,我们确实想要这个错误。

另一种选择是提供变量类型和默认参数,以有选择地禁用第三个参数,或强制指定它:

代码语言:javascript
复制
template< int dims, typename T >
class tweak_point_ctor_argument; // disallow general case of dims != 2,3

template< typename T >
class tweak_point_ctor_argument< 2, T > {
    tweak_point_ctor_argument() {} // private constructor
    typedef tweak_point_ctor_argument type;
    operator int() { return 0; }
    friend struct Point;
};

template< typename T >
class tweak_point_ctor_argument< 3, T > {
    typedef T type;
    friend struct Point;
};

    …
    Point( T X0, T X1, 
        typename tweak_point_ctor_argument< dims, T >::type X2
            = tweak_point_ctor_argument<dims, T>() ) {
        X[0] = X0;
        X[1] = X1;
        X[2] = X2;
    }

如果dims为2,则::type的计算结果为tweak_point_ctor_argument< 2, T >,除非使用默认参数,否则无法构造该值。因此,用户不可能使用第三个参数调用构造函数。如果dims为3,则::type的计算结果为T,导致默认参数初始值设定项无效,从而强制用户不使用它。

我还没有测试过这段代码,它只是演示了解决问题的各种方法,enable_if在这里是更好的方法。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2779155

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档