how to avoid undefined execution order for the constructors when using std::make_tuple
The trivial solution is not to use std::make_tuple(...)
in the first place but to construct a std::tuple<...>
directly: The order in which constructors for the members are called is well defined:
template <typename>
std::istream& dummy(std::istream& in) {
return in;
}
template <typename... T>
std::tuple<T...> parse(std::istream& in) {
return std::tuple<T...>(dummy<T>(in)...);
}
The function template dummy<T>()
is only used to have something to expand on. The order is imposed by construction order of the elements in the std::tuple<T...>
:
template <typename... T>
template <typename... U>
std::tuple<T...>::tuple(U...&& arg)
: members_(std::forward<U>(arg)...) { // NOTE: pseudo code - the real code is
} // somewhat more complex
Following the discussion below and Xeo's comment it seems that a better alternative is to use
template <typename... T>
std::tuple<T...> parse(std::istream& in) {
return std::tuple<T...>{ T(in)... };
}
The use of brace initialization works because the order of evaluation of the arguments in a brace initializer list is the order in which they appear. The semantics of T{...}
are described in 12.6.1 [class.explicit.init] paragraph 2 stating that it follows the rules of list initialization semantics (note: this has nothing to do with std::initializer_list which only works with homogenous types). The ordering constraint is in 8.5.4 [dcl.init.list] paragraph 4.
Tuple isn't being constructed in order?
std::tuple
construction order is currently unspecified.
A proposal for a concrete decision on its order has been submitted to the committee but until then the order should not be relied on.
How to guarantee order of argument evaluation when calling a function object?
What about a silly wrapper class like this:
struct OrderedCall
{
template <typename F, typename ...Args>
OrderedCall(F && f, Args &&... args)
{
std::forward<F>(f)(std::forward<Args>(args)...);
}
};
Usage:
void foo(int, char, bool);
OrderedCall{foo, 5, 'x', false};
If you want a return value, you could pass it in by reference (you'll need some trait to extract the return type), or store it in the object, to get an interface like:
auto x = OrderedCall{foo, 5, 'x', false}.get_result();
how to create (initialize) a std::tuple from an array when the constructors have the same argument type (a file path)
Using <redi/index_tuple.h>
to provide a compile-time integer sequence that produces the array indices in a pack expansion:
#include <tuple>
#include <assert.h>
#include <redi/index_tuple.h>
template<typename... T, unsigned... I>
inline std::tuple<T...>
myCreateTuple_impl(char** argv, redi::index_tuple<I...>)
{
return std::tuple<T...>(argv[I+1]...);
}
template<typename... T>
inline std::tuple<T...>
myCreateTuple(int argc, char** argv)
{
assert(argc > sizeof...(T));
return myCreateTuple_impl<T...>(argv, redi::to_index_tuple<T...>());
}
c++ : creating tuple & adding an element
The error that you see implies that one of the members that the tuple contains is not default-constructible. In such case you must initialise the member tuple with appropriate arguments to use the non-default constructors of the members of the tuple.
Also I would like to know if there any tuple method for adding a thing.
Nope. A tuple contains all of its members from the beginning of its lifetime until the end. There is no way to add or remove elements.
how to create (initialize) a std::tuple from an array when the constructors have the same argument type (a file path)
Using <redi/index_tuple.h>
to provide a compile-time integer sequence that produces the array indices in a pack expansion:
#include <tuple>
#include <assert.h>
#include <redi/index_tuple.h>
template<typename... T, unsigned... I>
inline std::tuple<T...>
myCreateTuple_impl(char** argv, redi::index_tuple<I...>)
{
return std::tuple<T...>(argv[I+1]...);
}
template<typename... T>
inline std::tuple<T...>
myCreateTuple(int argc, char** argv)
{
assert(argc > sizeof...(T));
return myCreateTuple_impl<T...>(argv, redi::to_index_tuple<T...>());
}
How to create a new variable and use it in std::tie at the same time?
@MikaelPersson had the right link. Basically, there's no great way to do this. Though, there are some clever ways based on N3802. Namely, use
// This comes from the N3802 proposal for C++
template <typename F, typename Tuple, size_t... I>
decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>) {
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
template <typename F, typename Tuple>
decltype(auto) apply(F&& f, Tuple&& t) {
using Indices =
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices{});
}
Then, write
// With compose
{
auto foo = apply([&bar](auto && foo,auto && bar_) {
bar=std::move(bar_);
return std::move(foo);
}, example());
}
And, yes, this whole thing is ugly, but the situation did come up in some instance I had. Nevertheless, as @MikaelPersson's link shows, this is a general issue and not one fully resolved yet.
Is there a way to expand and call a tuple of std::functions?
You have to remove the {}
in your funcs
assignment otherwise this will create an initializer_list
and not a tuple
static inline auto funcs = std::make_tuple(std::function<Ts()>()...);
Then you can call each tuple function with help of std::apply
and a generic variadic lambda:
auto call = [](auto&&...funcs) {
(funcs(),...);
};
int main()
{
A<int, float, char> l;
std::get<0>(l.funcs) = []() { cout << "Calling int()" << endl; return 1; };
std::get<1>(l.funcs) = []() { cout << "Calling float()" << endl; return 1.f; };
std::get<2>(l.funcs) = []() { cout << "Calling char()" << endl; return '1'; };
std::apply(call, l.funcs);
return 0;
}
See the live example: https://onlinegdb.com/HJfQ95TpS
C++ multiple forwarding of one reference: first copy and then move
I'm not sure the order-of-operations on the object initializations matter. Due to the perfect forwarding, no copies or moves are actually made (i.e. only lvalue references and rvalue references are passed around) until the std::tuple
constructor is called. And, at that point, it depends on the implementation details of std::tuple
.
Consider if instead of std::tuple
you used the following my_tup
struct:
template<typename T1, typename T2>
struct my_tup
{
template <typename A, typename B>
my_tup(A&& a, B&& b)
: t1(std::forward<A>(a)), t2(std::forward<B>(b))
{
}
T1 t1;
T2 t2;
};
This prints, as expected, "copy" and then "move" (coliru). But if instead you have:
template<typename T1, typename T2>
struct my_tup
{
template <typename A, typename B>
my_tup(A&& a, B&& b)
: t2(std::forward<B>(b)), t1(std::forward<A>(a))
{
}
T2 t2;
T1 t1;
};
Then this prints "move", then "copy", as std::tuple
does (coliru).
Likely due to the way the variadic template is expanded, std::tuple
must be dealing with the arguments in a right-to-left manner. I am not sure whether this is implementation-dependent or specified in the spec.
Related Topics
What Is the Size of an Enum Type Data in C++
Is There a Standard Way of Moving a Range into a Vector
Why Is There No 2-Byte Float and Does an Implementation Already Exist
Sharing Precompiled Headers Between Projects in Visual Studio
How to Use Multiple Versions of Gcc
Best Library for Statistics in C++
Allocating Vectors (Or Vectors of Vectors) Dynamically
How to Compare Two Vectors for Equality Element by Element in C++
How to Get the String Representation of Hresult Value Using Win API
How to Write a Std::String to a Utf-8 Text File
How Do Memory_Order_Seq_Cst and Memory_Order_Acq_Rel Differ
Do I Have to Bind a Udp Socket in My Client Program to Receive Data? (I Always Get Wsaeinval)
Project Error: Unknown Module(S) in Qt: Webkitwidgets
How to Extend a Lexical Cast to Support Enumerated Types
Extracting 3D Coordinates Given 2D Image Points, Depth Map and Camera Calibration Matrices