I encountered a problem which i dont really know how to solve. I want to pass variadic ammount of pairs in constructor, using { } braces, but for some reason im gettin compialtion error. I kept class as simple as possible
class MyPairs
{
public:
MyPairs(std::pair<char, int>&& pair)
{
pairs[pair.first] = pair.second;
}
template <typename ... Args>
MyPairs(std::pair<char, int>&& pair, Args&& ... args)
{
pairs[pair.first] = pair.second;
MyPairs(std::forward<Args>(args)...);
}
private:
std::map<char, int> pairs;
};
int main()
{
MyPairs p1( // okay, constructor expects pairs
std::pair<char, int>('a', 1),
std::pair<char, int>('b', 2)
);
MyPairs p2( // okay, compiler knows that it is std::pair<char, int> in constructor
{ 'c',3 }
);
MyPairs p3( // error, for some reason now he doesnt know it is std::pair<char, int>, std::pair<char, int>
{ 'd',6 },
{ 'e',5 }
);
}
Of course i can write std::pair<char, int>('a', 1) for every argument, but {'a', 1} is much more conventient.
Why compiler doesnt know how to match function when using { } braces ?
The easiest way is probably to use list initialization, and provide a constructor that accepts an std::initializer_list<T>.
In fact, that's how std::map's constructor (5) does it.
For example:
MyPairs(std::initializer_list<std::map<char, int>::value_type> init) : pairs(init) {}
See it live on Coliru
The only tricky bit here is that we cannot use a std::intializer_list<std::pair<char, int>> (because std::map<Key, T> defines value_type as std::pair<const Key, T>), since that will not be convertible to the std::intializer_list<std::pair<const char, int>> map's constructor is expecting.
To focus on this question:
Why compiler doesn't know how to match function when using { } braces?
The reason is because each parameter is deduced separately. For example, consider this:
template <typename A, typename B>
void foo(A a, B b) {
}
If I call foo(1, 3.14) then A will be deduced as int and B will be deduced as double. The two parameters are treated totally separately. The fact that the first one is int does not tell us anything about the second parameter. The compiler has to deduce the second parameter all on its own, independent of the first parameter.
This same logic applies to variadic templates. Each parameter in a variadic template is treated individually. The fact that the first parameter to your constructor is a std::pair<char, int> tells you nothing about the later parameters. You could, after all, try this:
MyPairs p(
{ 'd',6 },
1,
3.14,
"Hello, world!"
);
and the compiler would call the variadic constructor and deduce the variadic arguments as int, double, and a string. Each parameter is treated individually.
So when you try the following:
MyPairs p(
{ 'd',6 },
{ 'e',5 }
);
The compiler has to try and deduce the type of { 'e',5 }. And what type should it have? Remember, the compiler has to deduce its type separately from the first parameter. It's clear to us humans that you want it to be std::pair, but there compiler does not know that. So the compiler gives an error saying it doesn't know what to do with those extra parameters.
To give a slightly simpler example, your code is roughly equivalent to doing this:
template <typename A>
void bar(A a) {
}
bar({ 'd', 6 });
It's not clear to the compiler that you want A to be deduced as a std::pair. It could, after all, be a whole lot of different things.
Related
I'm trying to create a class that can store functions in a member tuple. But when trying to put lambdas inside of an object's tuple (through function pointers) I'm getting a error. Please explain, what I'm doing wrong and what is the proper way of releasing this idea. I think there should be an elegant and stylistically correct general solution (in terms of functional programming patterns) to avoid boilerplate code in class description, objects creation and filling them with functions.
#include <functional>
#include <string>
#include <iostream>
template<typename... ArgTypes>
class MyClass {
public:
//boolean function of some argument
template<typename Type> using Func = bool(Type const &);
//type for a tuple of pointers to templated boolean functions
template<typename... Types> using TupleOfFunctions = typename std::tuple<Func<Types>*...>;
//the tuple
TupleOfFunctions<ArgTypes...> _tuple;
//constructor
MyClass(TupleOfFunctions<ArgTypes...> t) : _tuple(t) {
}
};
int main(int argc, char** argv) {
MyClass<int, std::string> M({
[](int &arg) { return arg > 0; },
[](std::string &arg) { return arg == "abc"; }
});
std::cout << (*std::get<0>(M._tuple))(1);
std::cout << (*std::get<1>(M._tuple))("xyz");
return 0;
}
The error I get is
./test.cpp:26:3: error: no matching function for call to 'MyClass<int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::MyClass(<brace-enclosed initializer list>)'
26 | });
template<typename Type> using Func = bool(Type const &);
This line suggested functions taking in const type arguments. However:
[](int &arg) { return arg > 0; },
[](std::string &arg) { return arg == "abc"; }
These two lines suggested non-const arguments.
Either remove the const from the first line, or add const to the second two should solve it.
Could you, however, suggest some ideas of redesigning the class so that the boilerplate code of repeated explicit declaration of these types (in class template specification and lambda function arguments) can be avoided?
Part of the point of having lambda is anonymous function type. Actually trying to deduce a type of them, like what you did, was kind of going backward.
One way I would suggest to do this would be:
template<typename ... Lambdas>
class MyClass {
public:
std::tuple<Lambdas...> _tuple;
MyClass(Lambdas ... args) : _tuple(std::make_tuple(args ...)) {
}
};
Now you can use it like:
MyClass M(
[](const int &arg) { return arg > 0; },
[](const std::string &arg) { return arg == "abc"; }
);
Alternatively, you might be interested in a variant/visit pattern: https://godbolt.org/z/5Pdn1Ynqe
A braced-init-list, like {}, does not actually have a type. In the context of template deduction, you can only use them in certain cases - when deducing against initializer_list (where T is a function template parameter) or when the corresponding parameter is already deduced by something else. In this case, neither of those two things is true - so the compiler cannot figure out what ...ArgTypes is supposed to be.
I think you should use std::make_tuple and store as lambda as function pointer.
Live example
I've got some hierarchy of std::tuple.
I would like to write some access functions for all these tuples so that the resulting code is more readable.
So instead of writing:
std::get<2>(std::get<1>(std::get<0>(s)))
I would rather prefer to write
getNetName(getFirstNet(getFirstOutput(s)))
Now the point is to avoid writing these access functions twice -- for constant parameters and for writeable parameters.
Can this be done?
And of course -- I want these access functions to be type-safe. There might be multiple tuples types to which std::get<0>() can be applied -- but I would rather prefer that getNetName() creates a compiler error if it is not applied to a net.
std::get already does exactly what you want, so your goal is to simply write an alias for an existing function. The trick is to perfect forward your argument and return value to ensure nothing is lost. For example :
#include <tuple>
template<class T>
decltype(auto) getFirstElem(T&& p_tuple)
{
return std::get<0>(std::forward<T>(p_tuple));
}
int main()
{
std::tuple<int, int> mutable_x = { 42, 24 };
const std::tuple<int, int> const_x = { 10, 20 };
// mutable_ref is a `int&`
auto&& mutable_ref = getFirstElem(mutable_x);
// const_ref is a `const int&`
auto&& const_ref = getFirstElem(const_x);
}
decltype(auto) ensure that the return value is perfect forwarded. This preserves the reference qualifier and the constness of the return type. Using auto would cause the return value to decay to the underlying value type (in this case int). auto&& is similarly used to capture the result without discarding reference qualifier or constness.
Edit : It seems there was a type safety component to the question I missed. This is easily fixed by introducing a static_assert and std::is_same to compare the argument type with the expected type. It's important to remove reference qualifiers and cv modifiers to ensure the comparison is correct.
template<class T>
decltype(auto) getFirstElem(T&& p_tuple)
{
using t_expected = std::tuple<int, int>;
// Verify that the tuple matches the expectations
using t_tuple_clean = std::remove_cv_t<std::remove_reference_t<T>>;
static_assert(std::is_same<t_expected, t_tuple_clean>::value, "Unexpected tuple type");
return std::get<0>(std::forward<T>(p_tuple));
}
Unfortunately, the error message will usually be pretty long. Unfortunately I don't see a way to write this where the compiler's built-in argument matching could be used (which would generate clearer error messages). Perfect forwarding requires that the argument be a template type. Otherwise, you would need two overloads (one for const and one for non-const arguments) which would violate the single-function requirement of the question.
If you find it annoying to write out the check for every function, you can write a helper which can be used to more easily write new access functions.
#include <tuple>
#include <type_traits>
template<size_t index, class t_expected, class t_tuple>
decltype(auto) getHelper(t_tuple&& p_tuple)
{
// Verify that the tuple matches the expectations
using t_tuple_clean = std::remove_cv_t<std::remove_reference_t<t_tuple>>;
static_assert(std::is_same<t_expected, t_tuple_clean>::value, "Unexpected tuple type");
// Forward to std::get
return std::get<index>(std::forward<t_tuple>(p_tuple));
}
template<class T>
decltype(auto) getFirstElem(T&& p_tuple)
{
return getHelper<0, std::tuple<int, int>>(std::forward<T>(p_tuple));
}
The access function will now fail with a compiler error if the wrong type of tuple is provided :
int main()
{
// Compiler error 'Unexpected tuple type'
std::tuple<double, int> bad_tuple{};
auto&& bad_ref = getFirstElem(bad_tuple);
}
sorry this is C++11 (complain to my boss)!
template<typename T, std::size_t I>
struct get
{ auto operator()(T &_r) const -> decltype(std::get<I>(_r))
{ return std::get<I>(_r);
}
auto operator()(const T &_r) const -> decltype(std::get<I>(_r))
{ return std::get<I>(_r);
}
};
and application:
typedef std::pair<
std::size_t, // starting value
std::size_t // size or ending value?
> dimension;
typedef get<dimension, 0> getDimensionStart;
typedef get<dimension, 1> getDimensionSize;
typedef std::pair<
std::string,
boost::optional<dimension> // if scalar, then this is empty
> port;
typedef get<port, 0> getPortName;
typedef get<port, 1> getPortDimension;
using this code would look like this:
const port s("name", dimension(0, 10));
std::cout << getDimensionStart()(*getPortDimension()(s)) << std::endl;
I have the following (not compilable) code:
template< size_t N >
void foo( std::array<int, N> )
{
// Code, where "N" is used.
}
int main()
{
foo( { 1,2 } );
}
Here, I want to pass an arbitrary number of ints to a function foo -- for convenience, I will use the std::initializer_list notation.
I tried to use an std::array to aggregate the ints (as shown in the code above), however, the compiler can not deduce the array size since the ints are passed as an std::initializer_list.
Using an std::initializer_list instead of an std::array also does not solve the problem since (in contrast to std::array) the size of the std::initializer_list is not captured as template argument.
Does anyone know which data structure can be used so that the ints can be passed by using the std::initializer_list notation and without passing the template argument N of foo explicitly?
Many thanks in advance
Thanks to core issue 1591, you can use
template <std::size_t N>
void foo( int const (&arr)[N] )
{
// Code, where "N" is used.
}
foo({1, 2, 3});
If using an initializer list is not a must, you can use variadic template parameter packs:
template<size_t S>
void foo_impl(array<int, S> const&)
{
cout << __PRETTY_FUNCTION__ << endl;
}
template<typename... Vals>
auto foo(Vals&&... vals) {
foo_impl<sizeof...(vals)>({ std::forward<Vals>(vals)... });
}
you'd call it as follows:
foo(1,2,3,4,5);
This defers common type checks until the initialization point of std::array (unless you add some admittedly ugly asserts), so you probably should prefer Columbo's answer.
Considering the following code snippet...
void boo(std::initializer_list<unsigned> l)
{
}
template <class T>
void foo(std::initializer_list<T> l)
{
//Even though T is convertable, initializer list is not...:-(
boo(move(l));
}
int main()
{
foo({1u,2u,3u}); //Compiles fine as expected
foo({1,2,3}); //Fails to compile at line 9... - could not convert...
return 0;
}
... I'm surprised that initializer_list<int> is not convertible to initializer_list<unsigned>, event though int converts to unsigned.
I've been wondering in what way one can write foo to allow the conversion. Can one somehow unwrap the list having the wrong type and recreate a new list with the right type?
Nope. Constructing an initializer list requires a compile-time known length, and consuming an initializer list you do not have a compile-time known length.
initializer lists are intended for "user-facing" operations, where the user is the consumer of your interface. Using them internally like that doesn't work well.
An approach you can use is to write an array_view<T> type that wraps a range of contiguous memory (an initializer list, a vector, a std array, or a C array are all examples of this) in a range-view like way (with begin, end, data, size, empty, front, back methods. Iterators are pointers).
Then give it implicit converting ctors from vector<T>&, vector<std::remove_const_t<T>> const&, initializer_list<std::remove_const_t<T>> etc.
void boo(array_view<const unsigned> l)
{
}
template <class T>
void foo(std::initializer_list<T> l)
{
boo(std::vector<unsigned>{l.begin(), l.end()});
}
goes an reallocates a new buffer of unsigned values based off whatever was in l and passes it to boo. boo consumes an array_view<unsigned const>, which can convert from a vector or an initializer_list of unsigned.
We can then write maybe_convert_list:
template <class T, class U, class...LowPrecidence>
std::vector<T> maybe_convert_list(std::initializer_list<U> l, LowPrecidence&&...)
{
return {l.begin(), l.end()};
}
template <class T>
std::initializer_list<T> maybe_convert_list(std::initializer_list<T> l)
{
return l;
}
template <class T>
void foo(std::initializer_list<T> l)
{
boo(maybe_convert_list<unsigned>(l));
}
or somesuch. It leaves initializer_list<unsigned> alone. For other types of lists, it converts it to a std::vector<unsigned>.
While you can't unpack initializer list during compile time (to perform neccessary conversion), you can create it the way you want it to be. Consider following code:
#include <initializer_list>
void boo(std::initializer_list<unsigned> l);
template <class... T>
void foo(T... l)
{
boo({static_cast<unsigned int>(l)...});
}
int main()
{
foo(1,2,3);
return 0;
}
A class Foo<T> is not convertible to Foo<U>, even though T is convertible to U. For the compiler, different types in the template instantiation give rise to instances of unrelated types.
So in your case, foo({1,2,3}) deduces T as int, so the argument of foo has the type initializer_list<int>. You then try to pass that to boo, which takes an initializer_list<unsigned>, which is unrelated to initializer_list<int>, hence the compile error.
You can probably avoid this headache via template specialization instead, i.e. specialize your foo for the unsigned type:
template<>
void foo<unsigned>(std::initializer_list<unsigned>)
{
// specialization here
}
In short, this conversion cannot be done. Once you have a std::initializer_list<int> object, there is no way to use it to synthesize a std::initializer_list<unsigned>. You can iterate through it but the problem is that the information about the size is not available statically so there's no way to generate from one std::initializer_list object a braced-enclosed list of initializers with which to construct a different std::initializer_list object.
If boo needs to receive std::initializer_list<unsigned>, then foo should have a parameter of type std::initializer_list<unsigned>. You can convert {1, 2, 3} to std::initializer_list<unsigned>. But once you deduce it as std::initializer_list<int> this possibility disappears.
What is the purpose of std::make_pair?
Why not just do std::pair<int, char>(0, 'a')?
Is there any difference between the two methods?
The difference is that with std::pair you need to specify the types of both elements, whereas std::make_pair will create a pair with the type of the elements that are passed to it, without you needing to tell it. That's what I could gather from various docs anyways.
See this example from http://www.cplusplus.com/reference/std/utility/make_pair/
pair <int,int> one;
pair <int,int> two;
one = make_pair (10,20);
two = make_pair (10.5,'A'); // ok: implicit conversion from pair<double,char>
Aside from the implicit conversion bonus of it, if you didn't use make_pair you'd have to do
one = pair<int,int>(10,20)
every time you assigned to one, which would be annoying over time...
As #MSalters replied above, you can now use curly braces to do this in C++11 (just verified this with a C++11 compiler):
pair<int, int> p = {1, 2};
Class template arguments could not be inferred from the constructor before C++17
Before C++17 you could not write something like:
std::pair p(1, 'a');
since that would infer template types from the constructor arguments, you had to write it explicitly as:
std::pair<int,char> p(1, 'a');
C++17 makes that syntax possible, and therefore make_pair redundant.
Before C++17, std::make_pair allowed us to write less verbose code:
MyLongClassName1 o1;
MyLongClassName2 o2;
auto p = std::make_pair(o1, o2);
instead of the more verbose:
std::pair<MyLongClassName1,MyLongClassName2> p{o1, o2};
which repeats the types, and can be very long.
Type inference works in that pre-C++17 case because make_pair is not a constructor.
make_pair is essentially equivalent to:
template<class T1, class T2>
std::pair<T1, T2> my_make_pair(T1 t1, T2 t2) {
return std::pair<T1, T2>(t1, t2);
}
The same concept applies to inserter vs insert_iterator.
See also:
Why not infer template parameter from constructor?
https://en.wikibooks.org/wiki/More_C++_Idioms/Object_Generator
Minimal example
To make things more concrete, we can observe the problem minimally with:
main.cpp
template <class MyType>
struct MyClass {
MyType i;
MyClass(MyType i) : i(i) {}
};
template<class MyType>
MyClass<MyType> make_my_class(MyType i) {
return MyClass<MyType>(i);
}
int main() {
MyClass<int> my_class(1);
}
then:
g++-8 -Wall -Wextra -Wpedantic -std=c++17 main.cpp
compiles happily, but:
g++-8 -Wall -Wextra -Wpedantic -std=c++14 main.cpp
fails with:
main.cpp: In function ‘int main()’:
main.cpp:13:13: error: missing template arguments before ‘my_class’
MyClass my_class(1);
^~~~~~~~
and requires instead to work:
MyClass<int> my_class(1);
or the helper:
auto my_class = make_my_class(1);
which uses a regular function instead of a constructor.
Difference for std::reference_wrapper
This comment mentions that std::make_pair unwraps std::reference_wrapper while the constructor does not, so that's one difference. TODO example.
Tested with GCC 8.1.0, Ubuntu 16.04.
There is no difference between using make_pair and explicitly calling the pair constructor with specified type arguments. std::make_pair is more convenient when the types are verbose because a template method has type deduction based on its given parameters.
For example,
std::vector< std::pair< std::vector<int>, std::vector<int> > > vecOfPair;
std::vector<int> emptyV;
// shorter
vecOfPair.push_back(std::make_pair(emptyV, emptyV));
// longer
vecOfPair.push_back(std::pair< std::vector<int>, std::vector<int> >(emptyV, emptyV));
It's worth noting that this is a common idiom in C++ template programming. It's known as the Object Generator idiom, you can find more information and a nice example here.
Edit As someone suggested in the comments (since removed) the following is a slightly modified extract from the link in case it breaks.
An Object Generator allows creation of objects without explicitly specifying their types. It is based on a useful property of function templates which class templates don't have: The type parameters of a function template are deduced automatically from its actual parameters. std::make_pair is a simple example that returns an instance of the std::pair template depending on the actual parameters of the std::make_pair function.
template <class T, class U>
std::pair <T, U>
make_pair(T t, U u)
{
return std::pair <T, U> (t,u);
}
make_pair creates an extra copy over the direct constructor. I always typedef my pairs to provide simple syntax.
This shows the difference (example by Rampal Chaudhary):
class Sample
{
static int _noOfObjects;
int _objectNo;
public:
Sample() :
_objectNo( _noOfObjects++ )
{
std::cout<<"Inside default constructor of object "<<_objectNo<<std::endl;
}
Sample( const Sample& sample) :
_objectNo( _noOfObjects++ )
{
std::cout<<"Inside copy constructor of object "<<_objectNo<<std::endl;
}
~Sample()
{
std::cout<<"Destroying object "<<_objectNo<<std::endl;
}
};
int Sample::_noOfObjects = 0;
int main(int argc, char* argv[])
{
Sample sample;
std::map<int,Sample> map;
map.insert( std::make_pair( 1, sample) );
//map.insert( std::pair<int,Sample>( 1, sample) );
return 0;
}
starting from c++11 just use uniform initialization for pairs. So instead of:
std::make_pair(1, 2);
or
std::pair<int, int>(1, 2);
just use
{1, 2};