Constructor arguments from a tuple - c++

If I have a struct like:
struct Thing
{
int x;
int y;
bool a;
bool b;
}
Then I can create a Thing object by doing: Thing t {1,2,true,false};. However, if I have a tuple then I am doing something like:
std::tuple<int, int, bool, bool> info = std::make_tuple(1,2,true,false);
Thing t { std::get<0>(info), std::get<1>(info).. // and so on
Is there a better way to do this?

We can create a generic factory function for creating aggregates from tuple-like types (std::tuple, std::pair, std::array, and arbitrary user-defined tuple-like objects in a structured bindings world†):
template <class T, class Tuple, size_t... Is>
T construct_from_tuple(Tuple&& tuple, std::index_sequence<Is...> ) {
return T{std::get<Is>(std::forward<Tuple>(tuple))...};
}
template <class T, class Tuple>
T construct_from_tuple(Tuple&& tuple) {
return construct_from_tuple<T>(std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{}
);
}
which in your case would be used as:
std::tuple<int, int, bool, bool> info = std::make_tuple(1,2,true,false);
Thing t = construct_from_tuple<Thing>(info); // or std::move(info)
This way, Thing can still be an aggregate (don't have to add constructor/assignments), and our solution solves the problem for many, many types.
As an improvement, we could add SFINAE to both overloads to ensure that they're not callable with invalid tuple types.
†Pending accepting wording of how decomposition will work, the qualified call to std::get<Is> may need to be changed to an unqualified call to get<Is> which has special lookup rules. For now, this is moot, since it's 2016 and we don't have structured bindings.
Update: In C++17, there is std::make_from_tuple().

If you are using c++14 you could make use of std::index_sequence creating helper function and struct as follows:
#include <tuple>
#include <utility>
struct Thing
{
int x;
int y;
bool a;
bool b;
};
template <class Thi, class Tup, class I = std::make_index_sequence<std::tuple_size<Tup>::value>>
struct Creator;
template <class Thi, class Tup, size_t... Is>
struct Creator<Thi, Tup, std::index_sequence<Is...> > {
static Thi create(const Tup &t) {
return {std::get<Is>(t)...};
}
};
template <class Thi, class Tup>
Thi create(const Tup &t) {
return Creator<Thi, Tup>::create(t);
}
int main() {
Thing thi = create<Thing>(std::make_tuple(1,2,true,false));
}
And the version without additional class (with one additional function):
#include <tuple>
#include <utility>
struct Thing
{
int x;
int y;
bool a;
bool b;
};
template <class Thi, class Tup, size_t... Is>
Thi create_impl(const Tup &t, std::index_sequence<Is...>) {
return {std::get<Is>(t)...};
}
template <class Thi, class Tup>
Thi create(const Tup &t) {
return create_impl<Thi, Tup>(t, std::make_index_sequence<std::tuple_size<Tup>::value>{});
}
int main() {
Thing thi = create<Thing>(std::make_tuple(1,2,true,false));
}
Yet another this time tricky version with just one helper function:
#include <tuple>
#include <utility>
struct Thing
{
int x;
int y;
bool a;
bool b;
};
template <class R, class T, size_t... Is>
R create(const T &t, std::index_sequence<Is...> = {}) {
if (std::tuple_size<T>::value == sizeof...(Is)) {
return {std::get<Is>(t)...};
}
return create<R>(t, std::make_index_sequence<std::tuple_size<T>::value>{});
}
int main() {
Thing thi = create<Thing>(std::make_tuple(1,2,true,false));
}

You may use std::tie:
Thing t;
std::tie(t.x, t.y, t.a, t.b) = info;

Here are other ways:
struct Thing
{
Thing(){}
Thing(int A_, int B_, int C_, int D_) //1
: A(A_), B(B_), C(C_), D(D_) {}
Thing(std::tuple<int,int,bool,bool> tuple) //3
: A(std::get<0>(tuple)), B(std::get<1>(tuple)),
C(std::get<2>(tuple)), D(std::get<3>(tuple)) {}
void tie_from_tuple(std::tuple<int,int,bool,bool> tuple) //4
{
std::tie(A,B,C,D) = tuple;
}
int A;
int B;
bool C;
bool D;
};
inline Thing tuple_to_thing(const std::tuple<int,int,bool,bool>& tuple) //2
{
return Thing{std::get<0>(tuple), std::get<1>(tuple),
std::get<2>(tuple), std::get<3>(tuple)};
}
int main()
{
auto info = std::make_tuple(1,2,true,false);
//1 make a constructor
Thing one(info);
//2 make a conversion function
Thing second = tuple_to_thing(info);
//3 don't use tuple (just use the struct itself if you have to pass it)
Thing three{1,2,true,false};
//4 make member function that uses std::tie
Thing four;
four.tie_from_tuple(info);
}

Provide an explicit constructor and assignment operator:
struct Thing
{
int x;
int y;
bool a;
bool b;
Thing() { }
Thing( int x, int y, bool a, bool b ): x(x), y(y), a(a), b(b) { }
Thing( const std::tuple <int, int, bool, bool> & t )
{
std::tie( x, y, a, b ) = t;
}
Thing& operator = ( const std::tuple <int, int, bool, bool> & t )
{
std::tie( x, y, a, b ) = t;
return *this;
}
};
Hope this helps.

Getting fancy with C++17 template argument deduction and using a proxy object (usage example at bottom):
#include <tuple>
using namespace std;
template <class Tuple>
class FromTuple {
// static constructor, used to unpack argument_pack
template <class Result, class From, size_t... indices>
static constexpr Result construct(index_sequence<indices...>, From&& from_tuple) {
return { get<indices>(forward<
decltype(from_tuple.arguments)>(from_tuple.arguments))... };
}
// used to select static constructor
using Indices = make_index_sequence<
tuple_size_v< remove_reference_t<Tuple> >>;
public:
// construct with actual tuple types only for parameter deduction
explicit constexpr FromTuple(const Tuple& arguments) : arguments(arguments) {}
explicit constexpr FromTuple(Tuple&& arguments) : arguments(move(arguments)) {}
// implicit cast operator delegates to static constructor
template <class Result>
constexpr operator Result() { return construct<Result>(Indices{}, *this); }
private:
Tuple arguments;
};
struct Thing { int x; int y; bool a; bool b; };
int main() {
std::tuple<int, int, bool, bool> info = std::make_tuple(1,2,true,false);
Thing thing0((Thing)FromTuple(info));
Thing thing1{(Thing)FromTuple(info)};
FromTuple from_info(info);
Thing thing2(from_info); // only way to avoid implicit cast operator
Thing thing3{(Thing)from_info};
return 0;
}
This generalizes to any class or struct, not just Thing. Tuple arguments will be passed into the constructor.

Related

Initializing array in struct

Assume we have some templated struct and sometimes it's template should be an array. How to initialize array in struct?
This
template<typename T>
struct A {
T x;
A(T x) : x(x) {}
};
int a[6];
A<decltype(a)> b(a);
generates error during compilation:
error: array initializer must be an initializer list
A(T x) : x(x) {}
^
UPD1. More complete code this thing is used in:
template<typename T>
struct A {
T x;
A(const T& x) : x(x) {}
A(const T&& x) : x(std::move(x)) {}
};
template<typename T>
A<typename std::remove_reference<T>::type> make_A(T&& a) {
return A<typename std::remove_reference<T>::type>(std::forward<T>(a));
}
auto a = make_A("abacaba");
A general solution is to provide a special constructor for arrays (enabled when T is an array) which copies the source array to the struct's array. It works, but discard move semantics for arrays.
#include <iostream>
#include <type_traits>
#include <string>
#include <tuple>
template<typename T>
struct A {
using value_type = std::remove_const_t<T>;
value_type x;
template<class U=T> A(const T& src, std::enable_if_t<!std::is_array_v<U>, int> = 0) : x(src) {}
template<class U=T> A(const T&& src, std::enable_if_t<!std::is_array_v<U>, int> = 0) : x(std::move(src)) {}
template<class U=T> A(const T& src, std::enable_if_t< std::is_array_v<U>, int> = 0) { std::copy(std::begin(src), std::end(src), std::begin(x)); }
};
template<typename T>
auto make_A(T&& a)
{ return A<typename std::remove_reference_t<T>>(std::forward<T>(a)); }
int main()
{
auto a1 = make_A("the answer");
std::ignore = a1;
auto a2 = make_A(42);
std::ignore = a2;
}
live demo
If you need T to be const for non-arrays sometimes, an improvement would be to define value_type as T if T is not an array and to std::remove_const_t<T> otherwise.
I suggest putting all the smarts into make_A, converting C-arrays to std::array<>s so that A<> needs only work with regular types:
namespace detail {
template<typename T, std::size_t... Is>
constexpr std::array<T, sizeof...(Is)> to_std_array(T const* const p,
std::index_sequence<Is...>)
{
return {{p[Is]...}};
}
}
template<typename T>
A<std::decay_t<T>> make_A(T&& x) {
return {std::forward<T>(x)};
}
template<typename T, std::size_t N>
A<std::array<T, N>> make_A(T const (& x)[N]) {
return {detail::to_std_array(x, std::make_index_sequence<N>{})};
}
Online Demo
If you're only concerned with hardcoded C-strings in particular (as opposed to C-arrays in general), consider converting to a string_view type rather than std::array<> to potentially save some space.
If it is a special behaviour you want to achieve for C-Strings exclusively, you may just add a special treatment:
// for all non-C-string cases
template<typename T, std::enable_if_t<!std::is_same_v<std::decay_t<T>, const char*>>* = nullptr>
A<typename std::remove_reference<T>::type> make_A(T&& a) {
return A<typename std::remove_reference<T>::type>(std::forward<T>(a));
}
// in case a C-string got passed
A<std::string> make_A(const std::string& str) {
return A<std::string>(str);
}
int main()
{
auto a = make_A("abacaba");
auto b = make_A(5);
}
With std::decay it works:
template<typename T>
A<typename std::decay<T>::type> make_A(T&& a) {
return A<typename std::decay<T>::type>(std::forward<T>(a));
}

How to arbitrarily enable or disable class method based on specific type?

I have a class like this:
struct X
{
enum Type { INT, FLOAT };
using val_t = std::tuple<int, float>;
X(Type t) : type(t) {}
Type type;
template<typename T>
X& operator =(T x)
{
// ???
static_assert(T is the same as `type');
// ???
std::get<type>(val) = x;
return *this;
}
val_t val;
};
Is it possible to assert at compile time if user tries to assign incompatible value?
For example:
X x1(X::INT);
x1 = 5; // OK
x1 = 3.14; // compilation error
Note: I prefer keeping the class as not a template because I need to keep its instances in collections (like std::vector etc).
You cannot: the value of type_ is run time data, compilation errors are not determined at runtime.
You could do:
enum Type { INT, FLOAT };
template<Type type_>
struct X {
using val_t = std::tuple<int, float>;
template<typename T>
X& operator =(T x) {
// ???
static_assert((type_==INT&&std::is_same<T,int>{})||(type_==FLOAT&&std::is_same<T,float>{}),
"types do not match"
);
std::get<T>(val) = x;
return *this;
}
val_t val;
};
X<INT> x1;
x1 = 5; // OK
x1 = 3.14; // compilation error
but I do not see much point.
One way would be to have a base type that does not do the checking just stores state, and a derived that knows its type.
struct Base{
enum {INT,FLOAT} Type;
// etc
};
template<Base::Type type>
struct Derived:private Base{
Derived():Base(type){}
using Base::some_method; // expose base methods
Base& get_base()&{return *this;}
Base get_base()&&{return std::move(*this);}
Base const& get_base()const&{return *this;}
template<class T>
Derived& operator=( T o){
static_assert((type_==INT&&std::is_same<T,int>{})||(type_==FLOAT&&std::is_same<T,float>{}),
"types do not match"
);
Base::operator=(std::move(o));
return *this;
}
};
Base does not check, at best it runtime asserts. Derived checks at compile time.
Niw when you know the type statically at compile time you use Derived<INT> d;; when you do not, or need to forget, use .get_base() or a Base b(type_enum_val);.
Considering that you have Type type; you can't assert at compiletime if type is INT or FLOAT or whatever you have. For that check you can only assert at runtime.
For everything else you can do a compiletime check, and a runtime check for using some template meta-programming:
namespace detail_tuple
{
template <typename T, std::size_t N, typename... ARGS>
struct get_by_type_impl {
enum {
kIdx = N
};
};
template <typename T, std::size_t N, typename... ARGS>
struct get_by_type_impl<T, N, T, ARGS...> {
enum {
kIdx = N
};
};
template <typename T, std::size_t N, typename U, typename... ARGS>
struct get_by_type_impl<T, N, U, ARGS...> {
enum {
kIdx = get_by_type_impl<T, N + 1, ARGS...>::kIdx
};
};
}
template <typename, typename>
struct validator;
template <typename T, typename... ARGS>
struct validator < T, std::tuple<ARGS...> >
{
static void validate(const std::size_t type_idx)
{
//compiletime checks
//get index of type T in ARGS...
constexpr auto ind = detail_tuple::get_by_type_impl<T, 0, ARGS...>::kIdx;
//check if index is valid
static_assert(ind < sizeof...(ARGS), "Type index out of bounds, type T is was not found in the tuple!");
//runtime checks
if (type_idx != ind)
std::cout << "Incompatible type index!\n";
}
};
struct X
{
enum Type
{
INT = 0,
FLOAT,
TYPE_COUNT,
};
using val_t = std::tuple<int, float>;
X(Type t) : type(t) {}
Type type;
template<typename T>
X& operator =(const T& x)
{
validator<T, val_t>::validate(type);
std::get<T>(val) = x;
return *this;
}
val_t val;
};
for that std::get uses type T instead of type

C++ passing parameter pack to class

I'd like to have a class that gets in it's Ctor unlimited parameters of the same type, and stores them into a vector. It should look like that:
class A(int a, int b, **N time parameter of type T**)
: data(**vector will get N times type T**)
{
}
protected:
vector<T> data;
How should I implement it? Solution could be in c++11/14
I got a few errors such as "parameter packs not expanded with ‘…' ", etc..
This code sample might be useful:
#include <vector>
#include <utility>
template<typename T>
class MyClass {
public:
template<typename ...Args>
MyClass(int a, int b, Args&& ...args) :data{ std::forward<Args>(args)... } {}
private:
std::vector<T> data;
};
int main() {
MyClass<char> sample(1, 2, 'a', 'b');
return 0;
}
[EDIT]: Added std::forward, added missing include for utility
Assuming that T could be anything, even something quite large or non-copyable, we'd want to:
preserve efficiency with perfect forwarding.
check types.
std::initializer_list satisfies 2 but not 1.
Simple variadic template expansion satisfies 1 and not 2.
This solution uses variadic template expansion and enable_if to enforce type compatibility.
#include <vector>
#include <utility>
#include <string>
namespace detail
{
constexpr bool all()
{
return true;
}
template<class...Rest>
constexpr bool all(bool b, Rest...rest)
{
return b and all(rest...);
};
}
template<class T>
class A
{
public:
using value_type = T; // say
template<class...Rest,
std::enable_if_t<detail::all(std::is_convertible<Rest, value_type>::value...)>* = nullptr>
A(int a, int b, Rest&&...rest)
: a_(a), b_(b)
{
this->fill(std::forward_as_tuple(std::forward<Rest>(rest)...),
std::make_index_sequence<sizeof...(Rest)>());
}
private:
template<class Tuple, std::size_t...Is>
void fill(Tuple&& t, std::index_sequence<Is...> seq)
{
data_.reserve(seq.size());
using expand = int[];
void(expand{ 0,
(data_.push_back(std::move(std::get<Is>(t))), 0)...
});
}
private:
int a_, b_;
std::vector<value_type> data_;
};
int main()
{
using namespace std::literals;
auto a = A<double>(1, 2, 4.3, 5.5, 6.6);
auto b = A<std::string>(1, 2, "the", "cat"s, "sat on the mat");
// error: no matching constructor...
// auto err = A<std::string>(1, 2, "the", "cat"s, 0.1);
}
Here you go:
#include <iostream>
#include <vector>
template<class T>
struct V
{
V(int n, std::initializer_list<T> l)
: data(l)
{
(void) n;
}
std::vector<T> data;
};
int main()
{
V<int> v(0,{1,2,3});
}
This is not a perfect example since one needs to construct an object with the weird syntax (n, {optional, arguments, of, same, type}) but it does provide wanted behavior.
The following example is similar to fr3nzy90's, but with the coming C++17 it will allow automatic deduction of T from the constructor arguments:
template <class T>
class MyContainer {
private:
std::vector<T> data;
public:
// Take the first T value explicitly so it can be used to deduce
// T from the constructor arguments (C++17 feature).
template <class... Ts>
MyContainer(int a, int b, T const & tval, Ts const &... tvals) :
data{tval, tvals...} {
…
}
// Special case, empty list, no implicit type deduction, because
// there is no T value to deduce it from.
MyContainer(int a, int b) {
…
}
};

How to write a wrapper that keeps rapping the output?

Basically, what I want to do is to hava a wrapper on some abstract class, then have the same wrapper class wrap around the output of any member function of that class. Keep doing that so that all objects are always wrapped.
Like (presudocode)
wrap<set(1..10)> (multiply,2)
(divide,3)
(plus,5)
(inverse)
(collect first 10)
.unwrap()
All lines above except the last line outputs wrap of something. It seems to be meanling less for now, but I believe then we can apply interesting things on it like:
wrap<someClass> dat;
dat.splitIntoThreads(2)
(thingA) .clone()
(thingB) (thing1)
(thingC) (thing2)
(thingD) (thing3)
.nothing() (thing4)
.sync() .exit()
.addMerge()
Here is my code for wrap:
template<class T>
struct wrap{
wrap(){}
wrap(T b){a=b;}
template<class L,class...R>
L operator() (L(T::*f)(R...),R...r){
return a.f(r...);
}
T a;
};
int main(){
wrap<testClass> a;
a(&testClass::f,13,'a');
}
It's working (gcc, c++0x). But when I replace the 6,7th line with the following (to actually wrap the result)
wrap<L> operator() (L(T::*f)(R...),R...r){
return wrap<L>(a.f(r...));
The compiler just sais: creating pointer to member function of non-class type "int".
How can I fix this? Is there any better to do this? Inheritence is one way but since we might have variable instance in one wrap, I think it's not useful.
EDIT
Here's my test class
struct testClass{
int f(int a,char b){
return a+b;
}
};
The reason why I'm using wrap L instead of wrap T is that the return type might not always be T.
You can try something like this:
#include <iostream>
#include <type_traits>
template<class T, bool = false>
struct wrap{
template <typename... Args>
wrap(Args&&... args) : a{std::forward<Args>(args)...} {};
template<class L, class...R>
wrap<L,std::is_fundamental<L>::value> operator() (L(T::*f)(R...),R...r){
return wrap<L,std::is_fundamental<L>::value > {(a.*f)(r...)};
}
T a;
};
template<class T>
struct wrap <T,true>{
template <typename... Args>
wrap(Args&&... args) : a{std::forward<Args>(args)...} {}
template<class L, class...R>
wrap<L,std::is_fundamental<L>::value> operator() (L(*f)(T a, R...), R...r){
return wrap<L,std::is_fundamental<L>::value > {f(a, r...)};
}
T a;
};
class testClass {
int m;
public:
testClass(int _m) : m{_m}{}
int multiAdd(int x, char y) {
m += x + y;
return m;
}
};
int add(int a, char b)
{
return a+b;
}
int main(){
wrap<testClass> a{0};
std::cout << a(&testClass::multiAdd,0,'d')(add,'a').a<<std::endl;
wrap<int, true> b{3};
std::cout << b(add,'a').a<<std::endl;
}
cpp.sh/6icg
It seems the error is in your testclass definition. Please check the below example.
Also, wrap in the operator() can be returned as reference. I don't see any need to create temporaries to be used for () chaining.
template<class T>
struct wrap{
template <typename... Args>
wrap(Args&&... args) : a{std::forward<Args>(args)...} {};
template<class L, class...R>
wrap<T>& operator() (L(T::*f)(R...),R...r){
a.f(r...);
return *this; //returning reference to current wrap object.
}
T a;
};
A test class to accumulate numbers.
class testClass {
int m;
public:
testClass(int _m) : m{_m}{}
int f(int x) {
m += x;
std::cout << ' ' << m;
return m;
}
};
An usage example:
int main(){
wrap<testClass> a{0};
a(&testClass::f,13)(&testClass::f, 11)(&testClass::f,3)(&testClass::f, 21);
}
Output of sum accumulated at each step:
13 24 27 48

Specializing a template on functions with different signatures?

I have a template that requires that I pass it a functor as a type parameter in order to perform some calculations. I would like to specialize this functor based on another function that I want to use to actually perform the calculations. Basically, I want to do this (which is not legal, I'm redefining the functor):
template<typename T, int (*func)(int)>
struct Functor
{
T val;
int operator()(int x) { return func(2); }
};
template<typename T, int (*func)(int, int)>
struct Functor
{
T val;
int operator()(int y) { return func(y, 2); }
};
Component<Functor<calculationFunction1>> comp1;
Component<Functor<calculationFunction2>> comp2;
auto result1 = comp1.Compute();
auto result2 = comp2.Compute();
I've tried using partial specialization to get this to work as well, but that doesn't seem to be legal, either. I'm not sure if it's possible to get what I want, since the two functions have differing signatures. What's the best way to achieve what I'm trying to do here?
How about:
template<typename T, typename SOME_FUNC_TYPE, SOME_FUNC_TYPE func >
struct Functor {};
typedef int (*SingleArgFunc)(int);
typedef int (*DoubleArgFunc)(int,int);
template<typename T, SingleArgFunc func>
struct Functor<T, SingleArgFunc, func>
{
T val;
int operator()(int x) { return func(2); }
};
template<typename T, DoubleArgFunc func>
struct Functor<T, DoubleArgFunc, func>
{
T val;
int operator()(int y) { return func(y, 2); }
};
int calculationFunction1 (int) { return 0; }
int calculationFunction2 (int, int) { return 0; }
template <typename FUNCTOR>
struct Component
{
int Compute (void) { return FUNCTOR()(0); }
};
Component<Functor<int, decltype(&calculationFunction1), calculationFunction1>> comp1;
Component<Functor<int, decltype(&calculationFunction2), calculationFunction2>> comp2;
auto result1 = comp1.Compute();
auto result2 = comp2.Compute();