How to cause a compile time error based on the size of an initializer_list?

浪子不回头ぞ 提交于 2019-12-25 01:53:05

问题


If I have a simple structure like

struct Point { int x, y; };

then I can do

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;
}

I now want to have the same behaviour when initializing Point with Point becoming a class but with x and y becoming private and using accessors, etc.

My first attempt was

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;

};

which kinda works but changes the compile time error into a runtime error. The question now is: How do I cause this class to behave the same as the simple struct, i.e. cause a compile time error when the initializer list is too large?

Looking around I found

  • static_assert on initializer_list::size()
  • Why is the size not a template argument of std::initializer_list?

Reading through the answers and comments I understand some of the constexpr and static_assert issues but am still no nearer to finding a solution to my question. Is it possible to cause a compile time error in C++11 (or C++14)? The compiler definitely knows all it needs to and it seems a likely enough thing for someone to want to do that the standard would have rolled it in somehow.


回答1:


By replacing the initializer list constructor with one like the following...

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

Note, I rewrote private variables x and y as m_x and m_y.

Now when you attempt to initialize a Point object with more than 2 arguments, you will get a compiler error similar to the one you had when Point was a struct.




回答2:


There is no compile time way to retrieve a std::initializer_list size, but you do not need it.

The initializer like syntax is named uniform initialization, part of the c++11 to unify, as the name self defined, the syntax.

Here a full example that work for your Point, as you can see, a constructor with arguments can be a match for a initializer list.

#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
}


来源:https://stackoverflow.com/questions/27982251/how-to-cause-a-compile-time-error-based-on-the-size-of-an-initializer-list

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!