问题
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