Welcome to 16892 Developer Community-Open, Learning,Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm trying to compile the following source code

#include <boost/property_tree/ptree.hpp>

int main() {
    boost::property_tree::ptree b;
    b.push_back(std::make_pair("a", "b"));

    return 9;
}

using the following compiler and instructions:

$ g++ ./source.cpp --std=c++11
$ g++ --version
g++ (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ # boost version is 1.55

and I'm getting the following error

./source.cpp: In function ‘int main()’:
./source.cpp:5:41: error: no matching function for call to ‘boost::property_tree::basic_ptree<std::basic_string<char>, std::basic_string<char> >::push_back(std::pair<const char*, const char*>)’
     b.push_back(std::make_pair("a", "b"));
                                     ^
In file included from /opt/boost/boost_1_55_0/boost/property_tree/ptree.hpp:516:0,
                 from ./source.cpp:1:
/opt/boost/boost_1_55_0/boost/property_tree/detail/ptree_implementation.hpp:362:9: note: candidate: boost::property_tree::basic_ptree<Key, Data, KeyCompare>::iterator boost::property_tree::basic_ptree<Key, Data, KeyCompare>::push_back(const value_type&) [with Key = std::basic_string<char>; Data = std::basic_string<char>; KeyCompare = std::less<std::basic_string<char> >; boost::property_tree::basic_ptree<Key, Data, KeyCompare>::value_type = std::pair<const std::basic_string<char>, boost::property_tree::basic_ptree<std::basic_string<char>, std::basic_string<char> > >]
         basic_ptree<K, D, C>::push_back(const value_type &value)
         ^
/opt/boost/boost_1_55_0/boost/property_tree/detail/ptree_implementation.hpp:362:9: note:   no known conversion for argument 1 from ‘std::pair<const char*, const char*>’ to ‘const value_type& {aka const std::pair<const std::basic_string<char>, boost::property_tree::basic_ptree<std::basic_string<char>, std::basic_string<char> > >&}’

NOTE: if I'm compiling this without --std=c++11 the error disappears

QUESTION: how may I compile it using c++11 standard or higher? I've found https://svn.boost.org/trac10/ticket/6785 , but in boost-1.55 it has been already fixed. thank you in advance!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
2.0k views
Welcome To Ask or Share your Answers For Others

1 Answer

Yes it does. The real change here is std::make_pair.

C++11 changed std::pair conversion rules, as well as the make_pair convenience function, which was made move-aware.

Analyzing It

Property Tree allows construction like this:

ptree pt("data");

to construct a tree with only value data and no child nodes. However, the indirect conversion for the second member of the pair doesn't apply in c++11 mode:

std::pair<std::string, ptree> v = std::make_pair("a", "b");

This line would have compiled in c++03, but no longer compiles in c++11

Isolating It

To find out whether it might be a libstdc++ or compiler bug, I isolated it into this minimal sample:

#include <utility>
#include <string>

struct X {
    X(std::string){}
};

int main() {
    std::pair<std::string, X> v = std::make_pair("a", "b");
}

Note the subtle point that it doesn't matter that the constructor isn't explicit like with the ptree(data_type const&) constructor. The additional implicit conversion char const(&)[] -> std::string required is enough to cause c++11 to reject the call.

This compiles in c++03 but fails in c++11 under GCC with libstdc++.

Just to check, clang agrees even when using libc++ instead of libstdc++.

At I bet this is by design and probably a result of making std::make_pair more precise and aware of move-semantics.

How To Fix

The workarounds are manifold. Convert explicitly:

b.push_back(std::make_pair("a", ptree("b")));

Making types explicit always helps:

b.push_back(ptree::value_type {"a", "b"});

Uniform initialization removes some cruft:

b.push_back({"a", ptree{"b"}});

For completeness, non-explicit constructors are more flexible:

b.push_back({"a", {}});

Or you can avoid the pair<> (value_type) interface altogether:

b.add_child("a", ptree{"b"});
b.add_child("a", {}).put_value("b");

But the real key here is that value nodes cannot have children. Why not just put the value?

b.add("a", "b");

This is my RECOMMENDATION. I feel std::pair<> is an implementation detail only useful to interoperate with other generic code. It hurts readability.

Live Demo

All the workarounds happily living together Live On Coliru

Prints

<?xml version="1.0" encoding="utf-8"?>
<a>b</a>
<a>b</a>
<a>b</a>
<a/>
<a>b</a>
<a>b</a>
<a>b</a>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to 16892 Developer Community-Open, Learning and Share
...