如何根据initializer_list的大小导致编译时错误?

时间:2015-01-16 10:46:31

标签: c++ c++11 c++14

如果我有一个简单的结构,如

struct Point { int x, y; };

然后我可以做

int main()
{
    Point p1 = { 10 };          // x = 10, y = 0
    Point p2 = { 10, 20 };      // x = 10, y = 20
    Point p3 = { 10, 20, 30 };  // Compile error: too many initializers for ‘Point’
    return 0;
}

我现在希望在Point初始化时Point成为一个类但xy变为私有并使用访问器等等时会产生相同的行为。

我的第一次尝试是

class Point
{
public:
    Point( std::initializer_list<int> init )
    {
        switch( init.size() )
        {
            case 0: x = 0; y = 0; break;
            case 1:
            {
                auto iter = init.begin();
                x = *iter++; y = 0;
                break;
            }
            case 2:
            {
                auto iter = init.begin();
                x = *iter++; y = *iter++;
                break;
            }
            default:
                throw 0;
                break;
        }
    }
private:
    int x, y;

};

哪种有效但将编译时错误更改为运行时错误。现在的问题是:如何使该类的行为与简单结构相同,即当初始化列表太大时导致编译时错误?

环顾四周我找到了

阅读答案和评论我理解了一些constexprstatic_assert问题,但我仍然没有找到解决问题的方法。是否有可能在C ++ 11(或C ++ 14)中导致编译时错误?编译器肯定知道它需要的所有内容,对于某人来说似乎可能已经足够了,标准会以某种方式将其推出。

2 个答案:

答案 0 :(得分:3)

将初始化列表构造函数替换为以下内容...

Point(int x, int y) :m_x(x), m_y(y) {}

注意,我将私有变量x和y重写为m_x和m_y。

现在,当您尝试初始化具有2个以上参数的Point对象时,您将得到类似于Point是结构时的编译器错误。

答案 1 :(得分:0)

没有编译时间方法来检索std::initializer_list大小,但您不需要它。

初始化器之类的语法命名为uniform initialization,是c ++ 11的一部分,用于统一,作为自定义名称的语法。

这里有一个适用于Point的完整示例,如您所见,带参数的构造函数可以与初始化列表匹配。

#include <iostream>

class Point {
public:
    Point() = default;

    Point( int x, int y ) : x_{x}, y_{y} {}
    Point( int x ) : x_(x) {}

    // or in your case, you can use a default argument
    //Point( int x, int y = int{} ) : x_{x}, y_{y} {}

    int X() const { return x_; }
    int Y() const { return y_; }
private:
    int x_{};
    int y_{};
};

void DisplayPoint( Point const & p) {
    std::cout << "( " << p.X() << ", " << p.Y() << " )" << std::endl;
}

Point GetAPoint() {
    return { 3, 5 };
}

int main() {
    DisplayPoint( {} );
    DisplayPoint( { 1 } );
    DisplayPoint( { 1, 2 } );
    DisplayPoint( GetAPoint() );
    DisplayPoint( Point( 5, 3 ) ); // pre c++11
    DisplayPoint( Point{ 5, 3 } ); // in the case the constructor is explicit
}