Question

I'm compiling with g++ 4.4.7 (and can't go any higher currently), and using the -std=gnu++0x compiler switch, which should allow the syntax of the third line.

typedef std::vector<CI_RecordInfo_Pair>   CI_RecordInfo_Vector;
typedef std::vector<std::pair<std::string, CI_RecordInfo_Vector*> > MgrBlks;
MgrBlks mgr_n_blks { {"T2M_NAME", NULL} };  // <--- line 59

However, the compiler complains as follows:

/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_pair.h: In constructor 'std::pair<_T1, _T2>::pair(_U1&&, _U2&&) [with _U1 = const char (&)[9], _U2 = long int, _T1 = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _T2 = CI_RecordInfo_Vector*]':
tom.cpp:59:   instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_pair.h:90: error: invalid conversion from 'long int' to 'CI_RecordInfo_Vector*'

I assume the "long int" is the NULL, and that for some reason I'm unable to convert it to a pointer. Yet elsewhere in a map of structs, I was able to compile something like

foo["X"] = { NULL, "bar", 12 }; // first element is a pointer

What is the difference?

Was it helpful?

Solution

The compiler is correct to reject this line:

MgrBlks mgr_n_blks { {"T2M_NAME", NULL} };

In C++11 std::pair has a template constructor that takes any argument types, then converts them to the members:

template<typename X, typename Y>
  pair(X&& x, Y&& y)
  : first(std::forward<X>(x)), second(std::forward<Y>(y))
  { }

NULL must be defined as 0 or 0L or something similar, so template argument deduction deduces the constructor's template arguments as const char* and (with GCC) long. The first argument type is convertible to std::string but long is not convertible to CI_RecordInfo_Vector*, so the constructor cannot be called.

For the other case with a map of structs there is no argument deduction, the RHS of the assignment must be convertible to the struct type, and in that case NULL is used to directly initialize the struct's first member, rather than first being deduced as a long and initializing a long, which cannot be converted to a pointer.

Do not use NULL in C++11, nullptr was invented to avoid exactly these problems, you should use it.

A possible workaround would be to cast the argument to the right type:

MgrBlks mgr_n_blks { {"T2M_NAME", (CI_RecordInfo_Vector*)NULL} };

but it's simpler and clearer just to use nullptr.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top