问题
How do I get the compiler to create temporaries, use the default constructor on them while not defining a function?
struct B {};
template<class T> struct C {};
template<class T,class T1>
struct A
{
A(const T& t,const T1& t1): m_t(t),m_t1(t1)
{
std::cout << __PRETTY_FUNCTION__ << "\n";
}
T m_t;
T1 m_t1;
};
int main() {
A< B , C<B> > a0( B() , C<B>() ); // Function definition
A< B , C<B> > a1( B b , C<B> c ); // dito, *at least A(const T& t,const T1& t1) not called
}
回答1:
You can wrap one of your arguments in an extra set of parentheses to stop it from being parsed as a function declaration:
A< B , C<B> > a0( (B()) , C<B>() );
Or even better, if you have access to a C++11 compiler, use brace initialization:
A< B , C<B> > a0{ B() , C<B>() };
回答2:
Two ways:
Initialise via assignment:
auto a0 = A<B, C<B>>(B(), C<B>());
Note that before C++17 this changes the semantics since it requires that a copy or move constructor is available for the type (even though that will be elided so the generated code is the same).
Use more parentheses around at least one argument:
A<B, C<B>> a0((B()), C<B>());
Either works. The second way might be unreadable and the “redundant” parentheses will surprise people not familiar with this behaviour.
回答3:
A< B , C<B> > a0((B()), (C<B>()));
// ^ ^ ^ ^
With the outer parentheses, each argument can only be an expression and not a declaration.
You only actually need this to be the case for one of the arguments to prevent the whole line from being parsed as an expression. You can choose which, or just do both.
Don't forget to write a comment alongside the code explaining that there's good reason for the "extra" parentheses, else god knows someone will come along and remove them some day in a "minor" VCS commit.
来源:https://stackoverflow.com/questions/13249694/avoid-the-most-vexing-parse