copy list initialization vs direct list initialization of temporary - c++11

Given the following struct:
struct ABC
{
ABC(){cout << "ABC" << endl;}
~ABC() noexcept {cout << "~ABC" << endl;}
ABC(ABC const&) {cout << "copy" << endl;}
ABC(ABC&&) noexcept {cout << "move" << endl;}
ABC& operator=(ABC const&){cout << "copy=" << endl;}
ABC& operator=(ABC&&) noexcept {cout << "move=" << endl;}
};
The output of:
std::pair<std::string, ABC> myPair{{}, {}};
is:
ABC
copy
~ABC
~ABC
While the output of:
std::pair<std::string, ABC> myPair{{}, ABC{}};
is:
ABC
move
~ABC
~ABC
In attempting to understand the difference between the two I think I have identified that the first case is using copy-list-initialization, while the second one uses direct-list-initialization of an unnamed temporary (numbers 7 and 2, respectively, in here: http://en.cppreference.com/w/cpp/language/list_initialization).
Searching for similar questions I've found this: Why does the standard differentiate between direct-list-initialization and copy-list-initialization? and this: Does copy list initialization invoke copy ctor conceptually?.
The answers in those questions discuss the fact that for copy-list-initialization, the use of an explicit constructor would render the code ill-formed. In fact, if I make ABC's default constructor explicit, my first example won't compile but that is (perhaps) a different matter.
So, the question is: Why is the temporary copied in the first case but moved in the second? What prevents it from being moved in the case of copy-list-initialization?
As a note, the following code:
std::pair<std::string, ABC> myPair = std::make_pair<string, ABC>({}, {});
Also results in a call to ABC's move constructor (and no copy constructor call), but different mechanisms may be involved.
You can try the code out (using gcc-4.9.2 in C++14 mode) at: https://ideone.com/Kc8xIn

In general, braced-init-lists like {} are not expressions and do not have a type. If you have a function template
template<typename T> void f(T);
and call f( {} ), no type will be deduced for T, and type deduction will fail.
On the other hand, ABC{} is a prvalue expression of type ABC (an "explicit type conversion in functional notation"). For a call like f( ABC{} ), the function template can deduce the type ABC from this expression.
In C++14, as well as in C++11, std::pair has the following constructors [pairs.pair]; T1 and T2 are the names of the template parameter of the std::pair class template:
pair(const pair&) = default;
pair(pair&&) = default;
constexpr pair();
constexpr pair(const T1& x, const T2& y);
template<class U, class V> constexpr pair(U&& x, V&& y);
template<class U, class V> constexpr pair(const pair<U, V>& p);
template<class U, class V> constexpr pair(pair<U, V>&& p);
template <class... Args1, class... Args2>
pair(piecewise_construct_t, tuple<Args1...>, tuple<Args2...>);
Note that there is a constructor
constexpr pair(const T1& x, const T2& y); // (C)
But no
constexpr pair(T1&& x, T2&& y);
instead, there is a perfectly forwarding
template<class U, class V> constexpr pair(U&& x, V&& y); // (P)
If you try to initialize a std::pair with two initializers where at least one of them is a braced-init-list, the constructor (P) is not viable since it cannot deduce its template arguments.
(C) is not a constructor template. Its parameter types T1 const& and T2 const& are fixed by the class template parameters. A reference to a constant type can be initialized from an empty braced-init-list. This creates a temporary object that is bound to the reference. As the type referred to is const, the (C) constructor will copy its arguments into the class' data members.
When you initialize a pair via std::pair<T,U>{ T{}, U{} }, the T{} and U{} are prvalue-expressions. The constructor template (P) can deduce their types and is viable. The instantiation produced after type deduction is a better match than the (C) constructor, because (P) will produce rvalue-reference parameters and bind the prvalue arguments to them. (C) on the other hand binds the prvalue arguments to lvalue-references.
Why then does the live example move the second argument when called via std::pair<T,U>{ {}, U{} }?
libstdc++ defines additional constructors. Below is an extract of its std::pair implementation from 78536ab78e, omitting function definitions, some comments, and SFINAE. _T1 and _T2 are the names of the template parameters of the std::pair class template.
_GLIBCXX_CONSTEXPR pair();
_GLIBCXX_CONSTEXPR pair(const _T1& __a, const _T2& __b); // (C)
template<class _U1, class _U2>
constexpr pair(const pair<_U1, _U2>& __p);
constexpr pair(const pair&) = default;
constexpr pair(pair&&) = default;
// DR 811.
template<class _U1>
constexpr pair(_U1&& __x, const _T2& __y); // (X)
template<class _U2>
constexpr pair(const _T1& __x, _U2&& __y); // (E) <=====================
template<class _U1, class _U2>
constexpr pair(_U1&& __x, _U2&& __y); // (P)
template<class _U1, class _U2>
constexpr pair(pair<_U1, _U2>&& __p);
template<typename... _Args1, typename... _Args2>
pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>);
Note the (E) constructor template: It will copy the first argument and perfectly forward the second. For an initialization like std::pair<T,U>{ {}, U{} }, it is viable because it only needs to deduce a type from the second argument. It is also a better match than (C) for the second argument, and hence a better match overall.
The "DR 811" comment is in the libstdc++ sources. It refers to LWG DR 811 which adds some SFINAE, but no new constructors.
The constructors (E) and (X) are a libstdc++ extension. I'm not sure if it's compliant, though.
libc++ on the other hand does not have this additional constructors. For the example std::pair<T,U>{ {}, U{} }, it will copy the second argument.
Live demo with both library implementations

Related

Recursively unpacking a template pack for a parameter-less function

I'm trying to create a struct template with a variadic template type pack, that can deduct the sum of the size of all types passed in.
Below you find a simplified example, in the real-world context, the size computed is used to create further member objects.
template <typename... Types>
struct OverallSize
{
template <typename FirstType, typename... NextTypes>
static constexpr size_t sizesum() { return sizeof (FirstType) + sizesum<NextTypes...>(); }
template <typename LastType>
static constexpr size_t sizesum() { return sizeof (LastType); }
static constexpr size_t size = sizesum<Types...>();
};
// Should work e.g. like this
auto s = OverallSize<int, float, char>::size; // s will be 9 on x86-64
I'm used to this recursive parameter unpacking approach when it comes to argument lists and assumed this works as well with argument-less functions and explicit template specification. However I get the following error when compiling with clang
Call to 'sizesum' is ambiguous
...
Candidate function [with FirstType = unsigned long, NextTypes = <>]
Candidate function [with LastType = unsigned long]
So it seems as if the last recursion iteration doesn't work here – not sure why the compiler doesn't simply chose the most obvious choice: The one with only one template type – just as it would happen if there was an actual template argument passed to the function.
So, what do I have to do to make this compile and work as desired?
For C++14 you can use SFINAE:
template <
typename FirstType,
typename... NextTypes,
std::enable_if_t<sizeof...(NextTypes) >= 1>* = nullptr >
static constexpr size_t sizesum() {
return sizeof (FirstType) + sizesum<NextTypes...>();
}
this template will be considered only if parameters pack has size >= 1.
Demo

C++11: Variadic template deduction logic

I have the following construct:
template <class... Args>
class some_class
{
public:
some_class() = default;
some_class(Args...) = delete;
~some_class() = default;
};
template<>
class some_class<void>
{
public:
some_class() = default;
~some_class() = default;
};
The reason for this is that I just want to allow the users to create objects using the default constructor, so for example:
some_class<int,float> b;
should work but
some_class<int,float> c(1,3.4);
should give me a compilation error.
At some point in time I also needed to create templates based on void hence, the specialization for void:
some_class<void> a;
But by mistake I have typed:
some_class<> d;
And suddenly my code stopped compiling and it gave me the error:
some_class<Args>::some_class(Args ...) [with Args = {}]’ cannot be
overloaded
some_class(Args...) = delete;
So here comes the question: I feel that I am wrong that I assume that some_class<> should be deduced to the void specialization... I just don't know why. Can please someone explain why some_class<> (ie: empty argument list) is different from some_class<void>? (A few lines from the standard will do :) )
https://ideone.com/o6u0D6
void is a type like any other (an incomplete type, to be precise). This means it can be used as a template argument for type template parameters normally. Taking your class template, these are all perfectly valid, and distinct, instantiations:
some_class<void>
some_class<void, void>
some_class<void, void, void>
some_class<void, char, void>
In the first case, the parameter pack Args has one element: void. In the second case, it has two elements: void and void. And so on.
This is quite different from the case some_class<>, in which case the parameter pack has zero elements. You can easily demonstrate this using sizeof...:
template <class... Pack>
struct Sizer
{
static constexpr size_t size = sizeof...(Pack);
};
int main()
{
std::cout << Sizer<>::size << ' ' << Sizer<void>::size << ' ' << Sizer<void, void>::size << std::endl;
}
This will output:
0 1 2
[Live example]
I can't really think of a relevant part of the standard to quote. Perhaps this (C++11 [temp.variadic] 14.5.3/1):
A template parameter pack is a template parameter that accepts zero or more template arguments. [ Example:
template<class ... Types> struct Tuple { };
Tuple<> t0; // Types contains no arguments
Tuple<int> t1; // Types contains one argument: int
Tuple<int, float> t2; // Types contains two arguments: int and float
Tuple<0> error; // error: 0 is not a type
—end example ]

std::map of non-movable objects [duplicate]

The following code will not compile on gcc 4.8.2.
The problem is that this code will attempt to copy construct an std::pair<int, A> which can't happen due to struct A missing copy and move constructors.
Is gcc failing here or am I missing something?
#include <map>
struct A
{
int bla;
A(int blub):bla(blub){}
A(A&&) = delete;
A(const A&) = delete;
A& operator=(A&&) = delete;
A& operator=(const A&) = delete;
};
int main()
{
std::map<int, A> map;
map.emplace(1, 2); // doesn't work
map.emplace(std::piecewise_construct,
std::forward_as_tuple(1),
std::forward_as_tuple(2)
); // works like a charm
return 0;
}
As far as I can tell, the issue isn't caused by map::emplace, but by pair's constructors:
#include <map>
struct A
{
A(int) {}
A(A&&) = delete;
A(A const&) = delete;
};
int main()
{
std::pair<int, A> x(1, 4); // error
}
This code example doesn't compile, neither with coliru's g++4.8.1 nor with clang++3.5, which are both using libstdc++, as far as I can tell.
The issue is rooted in the fact that although we can construct
A t(4);
that is, std::is_constructible<A, int>::value == true, we cannot implicitly convert an int to an A [conv]/3
An expression e can be implicitly converted to a type T if and only if the declaration T t=e; is well-formed,
for some invented temporary variable t.
Note the copy-initialization (the =). This creates a temporary A and initializes t from this temporary, [dcl.init]/17. This initialization from a temporary tries to call the deleted move ctor of A, which makes the conversion ill-formed.
As we cannot convert from an int to an A, the constructor of pair that one would expect to be called is rejected by SFINAE. This behaviour is surprising, N4387 - Improving pair and tuple analyses and tries to improve the situation, by making the constructor explicit instead of rejecting it. N4387 has been voted into C++1z at the Lenexa meeting.
The following describes the C++11 rules.
The constructor I had expected to be called is described in [pairs.pair]/7-9
template<class U, class V> constexpr pair(U&& x, V&& y);
7 Requires: is_constructible<first_type, U&&>::value is true and
is_constructible<second_type, V&&>::value is true.
8 Effects: The
constructor initializes first with std::forward<U>(x) and second with
std::forward<V>(y).
9 Remarks: If U is not implicitly convertible to
first_type or V is not implicitly convertible to second_type this
constructor shall not participate in overload resolution.
Note the difference between is_constructible in the Requires section, and "is not implicitly convertible" in the Remarks section. The requirements are fulfilled to call this constructor, but it may not participate in overload resolution (= has to be rejected via SFINAE).
Therefore, overload resolution needs to select a "worse match", namely one whose second parameter is a A const&. A temporary is created from the int argument and bound to this reference, and the reference is used to initialize the pair data member (.second). The initialization tries to call the deleted copy ctor of A, and the construction of the pair is ill-formed.
libstdc++ has (as an extension) some nonstandard ctors. In the latest doxygen (and in 4.8.2), the constructor of pair that I had expected to be called (being surprised by the rules required by the Standard) is:
template<class _U1, class _U2,
class = typename enable_if<__and_<is_convertible<_U1, _T1>,
is_convertible<_U2, _T2>
>::value
>::type>
constexpr pair(_U1&& __x, _U2&& __y)
: first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { }
and the one that is actually called is the non-standard:
// DR 811.
template<class _U1,
class = typename enable_if<is_convertible<_U1, _T1>::value>::type>
constexpr pair(_U1&& __x, const _T2& __y)
: first(std::forward<_U1>(__x)), second(__y) { }
The program is ill-formed according to the Standard, it is not merely rejected by this non-standard ctor.
As a final remark, here's the specification of is_constructible and is_convertible.
is_constructible [meta.rel]/4
Given the following function prototype:
template <class T>
typename add_rvalue_reference<T>::type create();
the predicate condition for a template specialization is_constructible<T, Args...> shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t:
T t(create<Args>()...);
[Note: These tokens are never interpreted as a function declaration. — end note] Access checking is performed as if in a context unrelated to T and any of the Args. Only the validity of the immediate context of the variable initialization is considered.
is_convertible [meta.unary.prop]/6:
Given the following function prototype:
template <class T>
typename add_rvalue_reference<T>::type create();
the predicate condition for a template specialization is_convertible<From, To> shall be satisfied if and
only if the return expression in the following code would be well-formed, including any implicit conversions
to the return type of the function:
To test() {
return create<From>();
}
[Note: This requirement gives well defined results for reference types, void types, array types, and function types. — end note] Access checking is performed as if in a context unrelated to To and From. Only
the validity of the immediate context of the expression of the return-statement (including conversions to
the return type) is considered.
For your type A,
A t(create<int>());
is well-formed; however
A test() {
return create<int>();
}
creates a temporary of type A and tries to move that into the return-value (copy-initialization). That selects the deleted ctor A(A&&) and is therefore ill-formed.

c++11 std::function like functors incomplete type

I've stumbled upon something I can't get through since last week...
Having this:
template<typename> struct fx;
template<typename R, typename...Args>
struct fx<R(Args...)>
{
virtual R operator()(const Args & ...x) const = 0;
};
and this:
template<typename> struct fx_err;
// I feel here something is wrong, but I can't figure it out.
template<template<typename> class F, typename R, typename... Args>
struct fx_err< F<R(Args...)> > : fx<R(R,Args...)>
{
using fx_type = F<R(Args...)>;
fx_type f;
R operator ()(const R &y, const Args & ...x) const override
{
return y - f(x...);
}
};
and this:
struct example_fun : fx<int(int,int,int)>
{
int operator() (const int &a, const int &b, const int &c) const override
{
return a * b * c;
}
};
when finally I try to use it like:
fx_err<example_fun> example;
int err = example(24,2,3,4);
compiler throws error: 'example has incomplete type'.
Something similar works only if I do not specialize fx_err and use pointer to fx_type functor instead, but then I need to add constructor to grab the pointer itself which is not something I want.
It's very frustrating. What's wrong with this? Is it possible what I'm trying to achieve? Can anybody help?
Thanks in advance.
UPDATE:
here's example code to play around with for those willing to experiment with this example: http://pastebin.com/i3bRF8tB
The problem on line:
fx_err<example_fun> example;
is caused by the fact that example_fun is "passed" to fx_err, which selects the declaration:
template<typename> struct fx_err;
which is an incomplete type.
The specialization you provide:
// I feel here something is wrong, but I can't figure it out.
template<template<typename> class F, typename R, typename... Args>
struct fx_err< F<R(Args...)> > : fx<R(R,Args...)>
{ ... }
cannot be selected, because example_fun is not a template class as required by:
template<typename> class F
Avoid template template parameters if you can. They add more complexity, and less flexibility, than you probably want.
It looks like you're trying to match the form of the fx base class against its derived class. Partial specialization requires exact matches, it won't slice to the base class. And even if it did, this member would be of abstract class type:
using fx_type = F<R(Args...)>;
fx_type f; // same as fx<R(Args...)> which is abstract
The solution is to preserve the derived class, and tell the partial specialization how to find the base. Then the partial specialization can do pattern matching on the base class.
template<typename derived, typename base = typename derived::fx>
struct fx_err;
template<typename derived, template<typename> class F, typename R, typename... Args>
struct fx_err< derived, F<R(Args...)> > : F<R(R,Args...)>
Live solution: http://coliru.stacked-crooked.com/a/870172bcad0a9034
Of course, finding the base class by typename derived::fx sort-of begs the question of what base class template was used. In theory, you could have several templates of the same name, or derived could have a member typedef my_base fx; instead of inheriting from an fx specialization.
More likely, though, you don't need template<typename> class F at all.
template<typename derived, typename base = typename derived::fx>
struct fx_err;
template<typename derived, typename R, typename... Args>
struct fx_err< derived, fx<R(Args...)> > : fx<R(R,Args...)>
fx_err<example_fun> does not match your partial specialization because example_fun is not of the form F<R(Args...)>. It inherits a type of that form, but that's not the same thing.
When selecting specializations for class templates, implicit conversions aren't considered. Therefore example_fun isn't seen as a fx<...> by the compiler when matching the specializations and the primary (undefined) template is chosen over the other specialization.
To solve this you can expose an alias for the base class in the derived class:
struct example_fun : fx<int(int,int,int)>
{
using type = fx<int(int,int,int)>;
};
And now use this alias at the declaration site:
fx_err<example_fun::type> example;
int err = example(24,2,3,4);
You can even use a macro to avoid repeating the base class name:
template<class T> struct tag { using type = T; };
#define BASE_TAG(B) B, public tag<B>
struct example_fun : BASE_TAG(fx<int(int, int, int)>) {
// ...
};
Your basic problem is that template type pattern matching does not work like function overload template pattern matching. Inheritance is ignored, only the type passed in is pattern matched against.
So struct foo: some_template<some_args...> does not match some_template<some_args...> during template type pattern matching for the purpose of figuring out which specialization to use.
This lets us work with types as values in functions:
template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;
Now function template pattern matching works more like what you seem to be expecting:
template<template<class...>class Z, class...Args>
constexpr tag<Z<Args...>> get_template( Z<Args...>const& ) { return {}; }
takes a single argument, does template function pattern matching and deduction against it. This will look at parents of the type passed in. It tries to match Z<Args...> for some template Z.
It returns a tag<Z<Args...>>, which is a stateless type that just stores the type we need. We can then feed the above through an alias to extract that template expansion:
template<class T>
using get_template_t = type_t<decltype(get_template(std::declval<T>()))>;
which is most of the way there.
Next, we need some SFINAE helper magic:
template<class...>struct voider:tag<void>{};
template<class...Ts>using void_t=type_t<voider<Ts...>>;
std::void_t is C++14, and takes a bunch of types and throws them away, returning void instead. I do it in 2 lines because some compilers fail on the one-line version.
Ok, now we attack fx_err:
template<class,class=void> struct fx_err;
the second class=void lets us do FSINAE work. We start with your
template<template<class...>class F, class R, class...Args>
struct fx_err< F<R(Args...)>, void > : fx<R(R,Args...)>
{
using fx_type = F<R(Args...)>;
fx_type f;
R operator ()(const R &y, const Args & ...x) const override {
return y - f(x...);
}
};
and we also do this:
template<class T>
struct fx_err< T, void_t<get_template_t<T>>> : fx_err<get_template_t<T>>
{};
which I think should work. If it doesn't, we just need to add a test to exclude the direct T<F(Args...)> case from this specialization.

Template type deduction problem

I've got a variant class. It has a pair of constructors:
/// Construct and fill.
template <typename T>
inline
variant (const T& t)
{
YYASSERT (sizeof (T) <= S);
new (buffer.raw) T(t);
}
template <typename T>
inline
variant (T&& t)
{
YYASSERT (sizeof (T) <= S);
new (buffer.raw) T(std::move(t));
}
Now I've called those constructors in this code:
parser::symbol_type
parser::make_IDENTIFIER (const Wide::ParsedFile::Identifier*& v)
{
return symbol_type (token::IDENTIFIER, v);
}
symbol_type takes a variant as it's second argument in this specific constructor, and v is being implicitly converted.
However, MSVC will try to use the rvalue reference constructor instead of using the other constructor, resulting in a compilation error when it attempts to new a reference. Why is that, and how can I make it stop?
You generally should not overload a templated T&& function. You should instead have the single function which forwards:
template <typename T>
inline
variant (T&& t)
{
typedef typename std::remove_reference<T>::type Tr;
YYASSERT (sizeof (Tr) <= S);
new (buffer.raw) Tr(std::forward<T>(t));
}
This has the functionality of your two overloads, while avoiding the problem of picking the wrong one.
I believe (not positive) that these are the two variants in your overload set:
varaint<const Wide::ParsedFile::Identifier*>(const Wide::ParsedFile::Identifier*const&)
varaint<const Wide::ParsedFile::Identifier*&>(const Wide::ParsedFile::Identifier*&)
And the second one wins because it is more specialized than the first (I'm making an educated guess, I'm not 100% positive).
The second template would be a better match, because the const specifiers are in different places in your function and in the first constructor.
In the first overload you will have T being deduced as
const Wide::ParsedFile::Identifier*
And then creating a const reference to that type. That adds an extra const.

Resources