Related
Here's a watered down example of the code I'm try to compile:
#include <iostream>
#include <functional>
template <class F>
auto foo(F&& fun)
{
return [callback = std::forward<F>(fun)](auto&&... args) {
std::invoke(callback, std::forward<decltype(args)>(args)...);
};
}
int main()
{
std::string cur("running"), target("ok");
foo([s1 = cur, s2 = target](std::string const& arg) /*mutable*/ {
if (s1 == arg)
{
std::cout << s1 << std::endl;
}
})("not ok");
return 0;
}
put simply I have a function foo that accepts callables, and is supposed to build a new callable from them. For the sake of the example, above I'm just invoking the fun argument but in the real case there are some decorations done to the callable and the result is placed into a data structure that invokes such "actions" under some conditions.
This example compiles and works just fine. The problem manifests when trying to pass mutable lambdas to foo. When I uncomment the mutable keyword above, I get this compilation error:
main.cpp: In instantiation of 'foo<main()::<lambda(const string&)> >(main()::<lambda(const string&)>&&)::<lambda(auto:1&& ...)> [with auto:1 = {const char (&)[7]}]':
main.cpp:21:7: required from here
main.cpp:8:20: error: no matching function for call to 'invoke(const main()::<lambda(const string&)>&, const char [7])'
8 | std::invoke(callback, std::forward<decltype(args)>(args)...);
| ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from main.cpp:2:
/usr/local/include/c++/11.2.0/functional:94:5: note: candidate: 'template<class _Callable, class ... _Args> std::invoke_result_t<_Callable, _Args ...> std::invoke(_Callable&&, _Args&& ...)'
94 | invoke(_Callable&& __fn, _Args&&... __args)
| ^~~~~~
/usr/local/include/c++/11.2.0/functional:94:5: note: template argument deduction/substitution failed:
In file included from /usr/local/include/c++/11.2.0/bits/move.h:57,
from /usr/local/include/c++/11.2.0/bits/nested_exception.h:40,
from /usr/local/include/c++/11.2.0/exception:148,
from /usr/local/include/c++/11.2.0/ios:39,
from /usr/local/include/c++/11.2.0/ostream:38,
from /usr/local/include/c++/11.2.0/iostream:39,
from main.cpp:1:
/usr/local/include/c++/11.2.0/type_traits: In substitution of 'template<class _Fn, class ... _Args> using invoke_result_t = typename std::invoke_result::type [with _Fn = const main()::<lambda(const string&)>&; _Args = {const char (&)[7]}]':
/usr/local/include/c++/11.2.0/functional:94:5: required by substitution of 'template<class _Callable, class ... _Args> std::invoke_result_t<_Callable, _Args ...> std::invoke(_Callable&&, _Args&& ...) [with _Callable = const main()::<lambda(const string&)>&; _Args = {const char (&)[7]}]'
main.cpp:8:20: required from 'foo<main()::<lambda(const string&)> >(main()::<lambda(const string&)>&&)::<lambda(auto:1&& ...)> [with auto:1 = {const char (&)[7]}]'
main.cpp:21:7: required from here
/usr/local/include/c++/11.2.0/type_traits:2933:11: error: no type named 'type' in 'struct std::invoke_result<const main()::<lambda(const string&)>&, const char (&)[7]>'
2933 | using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
| ^~~~~~~~~~~~~~~
Any idea why is that? Can my foo accept mutable lambdas as well?
Just add mutable to the lambda inside the foo:
template <class F>
auto foo(F&& fun)
{
return [callback = std::forward<F>(fun)](auto&&... args) mutable {
//^^^
std::invoke(callback, std::forward<decltype(args)>(args)...);
};
}
This question already has answers here:
how to do an if else depending type of type in c++ template? [duplicate]
(6 answers)
using std::is_same, why my function still can't work for 2 types
(4 answers)
Closed 1 year ago.
I want to fill a vector with different functions depending on the data type of vector. Now I have three types to consider: int, double, string. If I only consider int and double, the code works perfectly. But if I include string into the template, the code fails. I don't understand why the if statement for string doesn't work. Here is the code:
#include <iostream>
#include <vector>
#include <map>
#include <string>
template <typename T>
void fillV(std::vector<T> &res) {
if (std::is_same<T, double>::value ) res.push_back(3.5);
else if (std::is_same<T, int>::value) res.push_back(2);
else if (std::is_same<T, std::string>::value) res.push_back(std::string("hello"));
}
int main()
{
std::vector<std::string> t;
std::vector<double> t1;
std::vector<int> t2;
fillV<std::string>(t);
fillV<double>(t1);
fillV<int>(t2);
std::cout << t[0] << "\n";
std::cout << t1[0] << "\n";
std::cout << t2[0] << "\n";
}
The error information is
input
stderr
Compilation failed due to following error(s).main.cpp: In instantiation of ‘void fillV(std::vector<T>&) [with T = std::basic_string<char>]’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',27)">main.cpp:27:25</span>: required from here
main.cpp:16:42: error: no matching function for call to ‘std::vector >::push_back(double)’
if (std::is_same<T, double>::value ) res.push_back(3.5);
^~~
In file included from /usr/include/c++/6/vector:64:0,
from main.cpp:10:
/usr/include/c++/6/bits/stl_vector.h:914:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::basic_string; _Alloc = std::allocator >; std::vector<_Tp, _Alloc>::value_type = std::basic_string]
push_back(const value_type& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:914:7: note: no known conversion for argument 1 from ‘double’ to ‘const value_type& {aka const std::basic_string&}’
/usr/include/c++/6/bits/stl_vector.h:932:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = std::basic_string; _Alloc = std::allocator >; std::vector<_Tp, _Alloc>::value_type = std::basic_string]
push_back(value_type&& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:932:7: note: no known conversion for argument 1 from ‘double’ to ‘std::vector >::value_type&& {aka std::basic_string&&}’
main.cpp:17:43: error: no matching function for call to ‘std::vector >::push_back(int)’
else if (std::is_same<T, int>::value) res.push_back(2);
^~~
In file included from /usr/include/c++/6/vector:64:0,
from main.cpp:10:
/usr/include/c++/6/bits/stl_vector.h:914:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::basic_string; _Alloc = std::allocator >; std::vector<_Tp, _Alloc>::value_type = std::basic_string]
push_back(const value_type& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:914:7: note: no known conversion for argument 1 from ‘int’ to ‘const value_type& {aka const std::basic_string&}’
/usr/include/c++/6/bits/stl_vector.h:932:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = std::basic_string; _Alloc = std::allocator >; std::vector<_Tp, _Alloc>::value_type = std::basic_string]
push_back(value_type&& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:932:7: note: no known conversion for argument 1 from ‘int’ to ‘std::vector >::value_type&& {aka std::basic_string&&}’
main.cpp: In instantiation of ‘void fillV(std::vector<T>&) [with T = double]’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',28)">main.cpp:28:21</span>: required from here
main.cpp:18:51: error: no matching function for call to ‘std::vector::push_back(std::string)’
else if (std::is_same<T, std::string>::value) res.push_back(std::string("hello"));
^~~
In file included from /usr/include/c++/6/vector:64:0,
from main.cpp:10:
/usr/include/c++/6/bits/stl_vector.h:914:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = double; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::value_type = double]
push_back(const value_type& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:914:7: note: no known conversion for argument 1 from ‘std::string {aka std::basic_string}’ to ‘const value_type& {aka const double&}’
/usr/include/c++/6/bits/stl_vector.h:932:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = double; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::value_type = double]
push_back(value_type&& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:932:7: note: no known conversion for argument 1 from ‘std::string {aka std::basic_string}’ to ‘std::vector::value_type&& {aka double&&}’
main.cpp: In instantiation of ‘void fillV(std::vector<T>&) [with T = int]’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',29)">main.cpp:29:18</span>: required from here
main.cpp:18:51: error: no matching function for call to ‘std::vector::push_back(std::string)’
else if (std::is_same<T, std::string>::value) res.push_back(std::string("hello"));
^~~
In file included from /usr/include/c++/6/vector:64:0,
from main.cpp:10:
/usr/include/c++/6/bits/stl_vector.h:914:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = int; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::value_type = int]
push_back(const value_type& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:914:7: note: no known conversion for argument 1 from ‘std::string {aka std::basic_string}’ to ‘const value_type& {aka const int&}’
/usr/include/c++/6/bits/stl_vector.h:932:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = int; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::value_type = int]
push_back(value_type&& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:932:7: note: no known conversion for argument 1 from ‘std::string {aka std::basic_string}’ to ‘std::vector::value_type&& {aka int&&}’
Updated on 04/14/2021:
Since I can't answer my own question, I will add one more solution other than the overloading, which is by Partial template specialization. It works before C++17. The code is inspired by the first answer, thank you.
template <typename T, int i>
struct test;
template <typename T>
struct test<T, 1> {
void fillV(std::vector<T> &res) {
res.push_back(3.5);
}
};
template <typename T>
struct test<T, 2> {
void fillV(std::vector<T> &res) {
res.push_back(2);
}
};
template <typename T>
struct test<T, 3> {
void fillV(std::vector<T> &res) {
res.push_back("Hello");
}
};
int main()
{
std::vector<std::string> t;
std::vector<double> t1;
std::vector<int32_t> t2;
test<double, 1> a1;
a1.fillV(t1);
test<int32_t, 2> a2;
a2.fillV(t2);
test<std::string, 3> a;
a.fillV(t);
std::cout << t[0] << "\n";
std::cout << t1[0] << "\n";
std::cout << t2[0] << "\n";
}
Updated on 04/17/2021:
Moreover, if overloading is used, the following code would be enough.
void fill_v(std::vector<double>& res) { res.push_back(3.5); }
void fill_v(std::vector<int>& res) { res.push_back(2); }
void fill_v(std::vector<std::string>& res) { res.push_back(std::string("hello")); }
int main()
{
std::vector<std::string> t;
std::vector<double> t1;
std::vector<int32_t> t2;
fillV(t1);
fillV(t2);
fillV(t);
std::cout << t[0] << "\n";
std::cout << t1[0] << "\n";
std::cout << t2[0] << "\n";
}
if performs dispatch at run-time. At compile time, all the if part and else part need to be valid whatever T is.
You can change to Constexpr If (since C++17).
If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.
If a constexpr if statement appears inside a templated entity, and if condition is not value-dependent after instantiation, the discarded statement is not instantiated when the enclosing template is instantiated.
E.g.
template <typename T>
void fillV(std::vector<T> &res) {
if constexpr (std::is_same<T, double>::value ) res.push_back(3.5);
else if constexpr (std::is_same<T, int>::value) res.push_back(2);
else if constexpr (std::is_same<T, std::string>::value) res.push_back(std::string("hello"));
}
LIVE
Before C++17, you can add some overloads processing different variants of std::vector. E.g.
void fill_v(std::vector<double>& res) { res.push_back(3.5); }
void fill_v(std::vector<int>& res) { res.push_back(2); }
void fill_v(std::vector<std::string>& res) { res.push_back(std::string("hello")); }
template <typename T>
void fillV(std::vector<T> &res) {
if (std::is_same<T, double>::value ) fill_v(res);
else if (std::is_same<T, int>::value) fill_v(res);
else if (std::is_same<T, std::string>::value) fill_v(res);
// or just
// fill_v(res);
}
Using Boost, I am trying to emplace() a key/value pair into a boost::container::map. The value needs multiple arguments for the constructor. From what I've been able to find, I need to use piecewise_construct and pass the constructor args in tuples. This works with std::map<K,V>, but I can't get it to work using boost::container::map<K,V> The closest Boost doc I can find shows boost::unordered_multimap<K,V>, but not a plain map<K,V>.
#include <map>
#include <boost/tuple/tuple.hpp>
#include <boost/container/map.hpp>
#include <boost/unordered_set.hpp>
class A {
public:
/**/ A( int ) { }
bool operator<( const A & ) const { return false; }
} ;
class B {
public:
/**/ B( int, const char * ) { }
} ;
int
main( int, char ** )
{
A a( 100 );
B b( 200, "foo" );
std::map<A,B> mgood;
mgood.emplace( std::piecewise_construct,
std::make_tuple( 100 ),
std::make_tuple( 200, "Hello" ) );
#if 1
boost::container::map<A,B> mbad;
mbad.emplace( boost::unordered::piecewise_construct,
boost::make_tuple( 300 ),
boost::make_tuple( 400, "World" ) );
#endif
}
The g++-4.9.2 error messages are impenetrable (to me, anyway):
make -k tst g++ -DBOOST_LOG_DYN_LINK -g -std=c++11 -c -o tst.o
tst.cc In file included from
/usr/local/include/boost/container/detail/tree.hpp:25:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/allocator_traits.hpp: In
instantiation of âstatic void
boost::container::allocator_traits::priv_construct(boost::move_detail::false_type,
Allocator&, T*, Args&& ...) [with T =
boost::container::container_detail::pair; Args = {const
boost::unordered::piecewise_construct_t&, boost::tuples::tuple, boost::tuples::tuple}; Allocator =
boost::container::new_allocator, void*, (boost::container::tree_type_enum)0u, true> >;
boost::move_detail::false_type =
boost::move_detail::integral_constant]â:
/usr/local/include/boost/container/allocator_traits.hpp:353:86:
required from âstatic void
boost::container::allocator_traits::construct(Allocator&,
T*, Args&& ...) [with T = boost::container::container_detail::pair; Args = {const boost::unordered::piecewise_construct_t&,
boost::tuples::tuple,
boost::tuples::tuple}; Allocator =
boost::container::new_allocator, void*, (boost::container::tree_type_enum)0u, true> >]â
/usr/local/include/boost/container/detail/node_alloc_holder.hpp:167:81:
required from
âboost::container::container_detail::node_alloc_holder::NodePtr
boost::container::container_detail::node_alloc_holder::create_node(Args&& ...) [with Args = {const
boost::unordered::piecewise_construct_t&, boost::tuples::tuple, boost::tuples::tuple}; Allocator =
boost::container::new_allocator >; ICont =
boost::intrusive::rbtree_impl, void*, (boost::container::tree_type_enum)0u, true>,
boost::intrusive::rbtree_node_traits,
(boost::intrusive::link_mode_type)0u, boost::intrusive::dft_tag, 3u>,
void,
boost::container::value_to_node_compare, void*, (boost::container::tree_type_enum)0u, true>,
boost::intrusive::tree_value_compare,
std::less,
boost::container::container_detail::select1st >
, long unsigned int, true, void>; boost::container::container_detail::node_alloc_holder::NodePtr =
boost::container::container_detail::tree_node,
void*, (boost::container::tree_type_enum)0u, true>]â
/usr/local/include/boost/container/detail/tree.hpp:922:94: required
from
âstd::pair,
Options:: tree_type, Options:: optimize_size>::type::iterator, false>,
bool> boost::container::container_detail::tree::emplace_unique(Args&& ...) [with Args =
{const boost::unordered::piecewise_construct_t&,
boost::tuples::tuple,
boost::tuples::tuple}; Key = A; T = std::pair;
KeyOfValue =
boost::container::container_detail::select1st >;
Compare = std::less; Allocator =
boost::container::new_allocator >; Options =
boost::container::tree_opt<(boost::container::tree_type_enum)0u,
true>; typename
boost::container::container_detail::intrusive_tree_type,
Options:: tree_type, Options:: optimize_size>::type::iterator =
boost::intrusive::tree_iterator, void*, (boost::container::tree_type_enum)0u, true>,
boost::intrusive::rbtree_node_traits,
(boost::intrusive::link_mode_type)0u, boost::intrusive::dft_tag, 3u>,
false>]â /usr/local/include/boost/container/map.hpp:665:72:
required from âstd::pair, boost::container::container_detail::select1st >, Compare, Allocator, MapOptions>::iterator, bool> boost::container::map::emplace(Args&& ...) [with Args = {const
boost::unordered::piecewise_construct_t&, boost::tuples::tuple, boost::tuples::tuple}; Key = A; T = B;
Compare = std::less; Allocator =
boost::container::new_allocator >; MapOptions =
boost::container::tree_opt<(boost::container::tree_type_enum)0u,
true>; typename boost::container::container_detail::tree,
boost::container::container_detail::select1st >, Compare, Allocator, MapOptions>::iterator = boost::container::container_detail::iterator_from_iiterator, void*, (boost::container::tree_type_enum)0u, true>,
boost::intrusive::rbtree_node_traits,
(boost::intrusive::link_mode_type)0u, boost::intrusive::dft_tag, 3u>,
false>, false>]â tst.cc:90:53: required from here
/usr/local/include/boost/container/allocator_traits.hpp:408:10: error:
no matching function for call to
âboost::container::container_detail::pair::pair(const
boost::unordered::piecewise_construct_t&, boost::tuples::tuple, boost::tuples::tuple)â
{ ::new((void)p, boost_container_new_t()) T(::boost::forward(args)...); }
^ /usr/local/include/boost/container/allocator_traits.hpp:408:10: note:
candidates are: In file included from
/usr/local/include/boost/container/detail/tree.hpp:36:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/detail/pair.hpp:146:4: note:
template
boost::container::container_detail::pair::pair(std::pair<_U1,
_U2>&&)
pair(BOOST_RV_REF_BEG std::pair BOOST_RV_REF_END p)
^ /usr/local/include/boost/container/detail/pair.hpp:146:4: note: template argument deduction/substitution failed: In file included from
/usr/local/include/boost/container/detail/tree.hpp:25:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/allocator_traits.hpp:408:10: note:
types âstd::pair<_T1, _T2>â and âconst
boost::unordered::piecewise_construct_tâ have incompatible
cv-qualifiers
{ ::new((void*)p, boost_container_new_t()) T(::boost::forward(args)...); }
^ In file included from /usr/local/include/boost/container/detail/tree.hpp:36:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/detail/pair.hpp:141:4: note:
boost::container::container_detail::pair::pair(std::pair<_T1,
_T2>&&) [with T1 = A; T2 = B]
pair(BOOST_RV_REF_BEG std::pair BOOST_RV_REF_END p)
^ /usr/local/include/boost/container/detail/pair.hpp:141:4: note: candidate expects 1 argument, 3 provided
/usr/local/include/boost/container/detail/pair.hpp:137:4: note:
template
boost::container::container_detail::pair::pair(const
std::pair<_U1, _U2>&)
pair(const std::pair& p)
^ /usr/local/include/boost/container/detail/pair.hpp:137:4: note: template argument deduction/substitution failed: In file included from
/usr/local/include/boost/container/detail/tree.hpp:25:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/allocator_traits.hpp:408:10: note:
âconst boost::unordered::piecewise_construct_tâ is not derived
from âconst std::pair<_T1, _T2>â
{ ::new((void*)p, boost_container_new_t()) T(::boost::forward(args)...); }
^ In file included from /usr/local/include/boost/container/detail/tree.hpp:36:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/detail/pair.hpp:132:4: note:
boost::container::container_detail::pair::pair(const
std::pair<_T1, _T2>&) [with T1 = A; T2 = B]
pair(const std::pair& x)
^ /usr/local/include/boost/container/detail/pair.hpp:132:4: note: candidate expects 1 argument, 3 provided
/usr/local/include/boost/container/detail/pair.hpp:126:4: note:
template
boost::container::container_detail::pair::pair(U&&, V&&)
pair(BOOST_FWD_REF(U) u, BOOST_FWD_REF(V) v)
^ /usr/local/include/boost/container/detail/pair.hpp:126:4: note: template argument deduction/substitution failed: In file included from
/usr/local/include/boost/container/detail/tree.hpp:25:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/allocator_traits.hpp:408:10: note:
candidate expects 2 arguments, 3 provided
{ ::new((void*)p, boost_container_new_t()) T(::boost::forward(args)...); }
^ In file included from /usr/local/include/boost/container/detail/tree.hpp:36:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/detail/pair.hpp:120:4: note:
boost::container::container_detail::pair::pair(const T1&,
const T2&) [with T1 = A; T2 = B]
pair(const T1 &t1, const T2 &t2)
^ /usr/local/include/boost/container/detail/pair.hpp:120:4: note: candidate expects 2 arguments, 3 provided
/usr/local/include/boost/container/detail/pair.hpp:115:4: note:
template
boost::container::container_detail::pair::pair(boost::container::container_detail::pair&&)
pair(BOOST_RV_REF_BEG pair BOOST_RV_REF_END p)
^ /usr/local/include/boost/container/detail/pair.hpp:115:4: note: template argument deduction/substitution failed: In file included from
/usr/local/include/boost/container/detail/tree.hpp:25:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/allocator_traits.hpp:408:10: note:
types âboost::container::container_detail::pairâ and
âconst boost::unordered::piecewise_construct_tâ have incompatible
cv-qualifiers
{ ::new((void*)p, boost_container_new_t()) T(::boost::forward(args)...); }
^ In file included from /usr/local/include/boost/container/detail/tree.hpp:36:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/detail/pair.hpp:110:4: note:
template
boost::container::container_detail::pair::pair(const
boost::container::container_detail::pair&)
pair(const pair &p)
^ /usr/local/include/boost/container/detail/pair.hpp:110:4: note: template argument deduction/substitution failed: In file included from
/usr/local/include/boost/container/detail/tree.hpp:25:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/allocator_traits.hpp:408:10: note:
âconst boost::unordered::piecewise_construct_tâ is not derived
from âconst boost::container::container_detail::pairâ
{ ::new((void*)p, boost_container_new_t()) T(::boost::forward(args)...); }
^ In file included from /usr/local/include/boost/container/detail/tree.hpp:36:0,
from /usr/local/include/boost/container/map.hpp:30,
from tst.cc:59: /usr/local/include/boost/container/detail/pair.hpp:105:4: note:
boost::container::container_detail::pair::pair(boost::container::container_detail::pair&&) [with T1
= A; T2 = B]
pair(BOOST_RV_REF(pair) p)
^ /usr/local/include/boost/container/detail/pair.hpp:105:4: note: candidate expects 1 argument, 3 provided
/usr/local/include/boost/container/detail/pair.hpp:100:4: note:
boost::container::container_detail::pair::pair(const
boost::container::container_detail::pair&) [with T1 = A; T2 =
B]
pair(const pair& x)
^ /usr/local/include/boost/container/detail/pair.hpp:100:4: note: candidate expects 1 argument, 3 provided
/usr/local/include/boost/container/detail/pair.hpp:95:4: note:
boost::container::container_detail::pair::pair() [with T1 = A;
T2 = B]
pair()
^ /usr/local/include/boost/container/detail/pair.hpp:95:4: note: candidate expects 0 arguments, 3 provided : recipe for target
'tst.o' failed make: *** [tst.o] Error 1 make: Target 'tst' not remade
because of errors.
Compilation exited abnormally with code 2 at Sat Apr 2 17:11:28
Can you point me in a useful direction? (I'd prefer not to mix boost and std containers; it should be possible to emplace into a boost::container::map, right?)
It appears that piecewise_construct is not implemented for boost::pair (which is the type for boost::container::map entries). See .../boost/container/detail/pair.hpp:151:
//piecewise_construct missing
//template <class U, class V> pair(pair<U, V>&& p);
//template <class... Args1, class... Args2>
// pair(piecewise_construct_t, tuple<Args1...> first_args,
// tuple<Args2...> second_args);
I guess the implementation for this is tough.
piecewise_construct support for both C++03 and C++11 capable compilers was added in commit:
https://github.com/boostorg/container/commit/79a75f470e75f35f5f2a91e10fcc67d03b0a2160
and will be officially released in Boost 1.62. The following code compiles fine:
#include <boost/tuple/tuple.hpp>
#include <tuple>
#include <boost/container/map.hpp>
class A {
public:
/**/ A( int ) { }
bool operator<( const A & ) const { return false; }
} ;
class B {
public:
/**/ B( int, const char * ) { }
} ;
int main( int, char *[] )
{
A a( 100 );
B b( 200, "foo" );
boost::container::map<A,B> m;
//1) Both Boost.Tuple and std tuple supported
//2) std:: or boost::container::piecewise_construct supported
m.emplace( boost::container::piecewise_construct,
boost::make_tuple( 300 ),
boost::make_tuple( 400, "World" ) );
m.emplace( std::piecewise_construct,
std::make_tuple( 400 ),
std::make_tuple( 500, "World2" ) );
}
I'm not clear why it is legal to assign tuple<X,Y>=pair<X,Y>
But it is illegal to assign pair<X,Y>=tuple<X,Y>
std::pair<int, double> x { 1 , 5.5};
std::tuple<int, double> y { 1 , 5.5};
int a;
double b;
std::tie(a,b) = x;
std::tie(a,b) = y;
x = y; // THIS LINE (line 12)
y = x; // but this is fine ???
Shouldn't this be symmetrical?
Using g++ 4.8.1 gives the following errors:
tp.cpp:12:4: error: no match for operator= (operand types are std::pair<int, double> and std::tuple<int, double>)
x = y;
^
tp.cpp:12:4: note: candidates are:
In file included from /opt/gcc-4.8.1/include/c++/4.8.1/utility:70:0,
from /opt/gcc-4.8.1/include/c++/4.8.1/tuple:38,
from tp.cpp:1:
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:158:7: note: std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(const std::pair<_T1, _T2>&) [with _T1 = int; _T2 = double]
operator=(const pair& __p)
^
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:158:7: note: no known conversion for argument 1 from std::tuple<int, double> to const std::pair<int, double>&
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:166:7: note: std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1, _T2>&&) [with _T1 = int; _T2 = double]
operator=(pair&& __p)
^
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:166:7: note: no known conversion for argument 1 from std::tuple<int, double> to std::pair<int, double>&&
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:177:2: note: template<class _U1, class _U2> std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(const std::pair<_U1, _U2>&) [with _U1 = _U1; _U2 = _U2; _T1 = int; _T2 = double]
operator=(const pair<_U1, _U2>& __p)
^
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:177:2: note: template argument deduction/substitution failed:
tp.cpp:12:4: note: std::tuple<int, double> is not derived from const std::pair<_T1, _T2>
x = y;
^
In file included from /opt/gcc-4.8.1/include/c++/4.8.1/utility:70:0,
from /opt/gcc-4.8.1/include/c++/4.8.1/tuple:38,
from tp.cpp:1:
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:186:2: note: template<class _U1, class _U2> std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_U1, _U2>&&) [with _U1 = _U1; _U2 = _U2; _T1 = int; _T2 = double]
operator=(pair<_U1, _U2>&& __p)
^
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:186:2: note: template argument deduction/substitution failed:
tp.cpp:12:4: note: std::tuple<int, double> is not derived from std::pair<_T1, _T2>
x = y;
^
I think this is another case of:
No one proposed it.
Fwiw, your code works with libc++ (as an extension). libc++ implemented a "tuple-like" concept which includes tuple, pair and array, and then has member templates (on tuple and pair) that operate on "tuple-like" types. The approach hasn't been completely without problems, but it does seem promising.
I'm not clear why it is legal to assign tuple<X,Y>=pair<X,Y>
But it is illegal to assign pair<X,Y>=tuple<X,Y>
std::pair<int, double> x { 1 , 5.5};
std::tuple<int, double> y { 1 , 5.5};
int a;
double b;
std::tie(a,b) = x;
std::tie(a,b) = y;
x = y; // THIS LINE (line 12)
y = x; // but this is fine ???
Shouldn't this be symmetrical?
Using g++ 4.8.1 gives the following errors:
tp.cpp:12:4: error: no match for operator= (operand types are std::pair<int, double> and std::tuple<int, double>)
x = y;
^
tp.cpp:12:4: note: candidates are:
In file included from /opt/gcc-4.8.1/include/c++/4.8.1/utility:70:0,
from /opt/gcc-4.8.1/include/c++/4.8.1/tuple:38,
from tp.cpp:1:
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:158:7: note: std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(const std::pair<_T1, _T2>&) [with _T1 = int; _T2 = double]
operator=(const pair& __p)
^
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:158:7: note: no known conversion for argument 1 from std::tuple<int, double> to const std::pair<int, double>&
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:166:7: note: std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1, _T2>&&) [with _T1 = int; _T2 = double]
operator=(pair&& __p)
^
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:166:7: note: no known conversion for argument 1 from std::tuple<int, double> to std::pair<int, double>&&
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:177:2: note: template<class _U1, class _U2> std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(const std::pair<_U1, _U2>&) [with _U1 = _U1; _U2 = _U2; _T1 = int; _T2 = double]
operator=(const pair<_U1, _U2>& __p)
^
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:177:2: note: template argument deduction/substitution failed:
tp.cpp:12:4: note: std::tuple<int, double> is not derived from const std::pair<_T1, _T2>
x = y;
^
In file included from /opt/gcc-4.8.1/include/c++/4.8.1/utility:70:0,
from /opt/gcc-4.8.1/include/c++/4.8.1/tuple:38,
from tp.cpp:1:
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:186:2: note: template<class _U1, class _U2> std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_U1, _U2>&&) [with _U1 = _U1; _U2 = _U2; _T1 = int; _T2 = double]
operator=(pair<_U1, _U2>&& __p)
^
/opt/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:186:2: note: template argument deduction/substitution failed:
tp.cpp:12:4: note: std::tuple<int, double> is not derived from std::pair<_T1, _T2>
x = y;
^
I think this is another case of:
No one proposed it.
Fwiw, your code works with libc++ (as an extension). libc++ implemented a "tuple-like" concept which includes tuple, pair and array, and then has member templates (on tuple and pair) that operate on "tuple-like" types. The approach hasn't been completely without problems, but it does seem promising.