I have two questions about the code below:
why version / * 1 * / compiles under g++ and version / * 2 * / not?
why this code does not compile in clang?
I know How to fix it. but I want to understand why it does not work.
#include <boost/test/unit_test.hpp>
template<typename T,typename Cmp>
class queue{
public:
queue(Cmp c):cmp(c){};
void push(T a){
cmp(a,a);
}
Cmp cmp;
};
template<typename T>
void fun(T a){
class decreasing_order
{
public:
decreasing_order(std::vector<T> BBB):AAA(BBB) {}
std::vector<T> AAA;
bool operator() (const T & lhs, const T & rhs) const
{
return AAA[lhs]<AAA[rhs];
}
};
std::vector<T> tab;
queue<T, decreasing_order >uncoveredSetQueue((decreasing_order(tab)));/*1*/
// queue<T, decreasing_order >uncoveredSetQueue( decreasing_order(tab) );/*2*/
uncoveredSetQueue.push(a);
}
BOOST_AUTO_TEST_CASE(TestX) {
fun(1);
}
In clang i got the following error:
test.cpp:25:20: error:
'fun(int)::decreasing_order::operator()(const int &, const int
&)::decreasing_order::AAA' is not a member of class 'const
decreasing_order'
return AAA[lhs]<AAA[rhs];
^
/home/piotr/git/paal/test/greedy/test.cpp:10:9: note: in instantiation of
member function 'fun(int)::decreasing_order::operator()' requested
here
cmp(a,a);
^
/home/piotr/git/paal/test/greedy/test.cpp:30:23: note: in instantiation
of member function 'queue<int, decreasing_order>::push' requested
here
uncoveredSetQueue.push(a);
^
/home/piotr/git/paal/test/greedy/test.cpp:35:5: note: in instantiation of
function template specialization 'fun<int>' requested here
fun(1);
^
1 error generated.
I using g++ 4.8.1 and clang 3.4-1.
queue<T, decreasing_order >uncoveredSetQueue( decreasing_order(tab) );/*2*/
is an example of the Most Vexing Parse: it declares a function named uncoveredSetQueue
which takes an argument (here named tab
) of type decreasing_order
and returning queue<T, decreasing_order>
. As you found, adding parentheses avoids the Most Vexing Parse. You could also replace the parentheses with {}
to use uniform initialization syntax.
The clang error message looks like a compiler bug to me. Most likely it doesn't correctly handle some consequences of using a local type as a template parameter (which was not allowed in C++03, and is a new C++11 feature).