I have a template class where each template argument stands for one type of value the internal computation can handle. Templates (instead of function overloading) are needed because the values are passed as boost::any and their types are not clear before runtime.
To properly cast to the correct types, I would like to have a member list for each variadic argument type, something like this:
template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2>
class MyClass {
std::vector<T1> m_argumentsOfType1;
std::vector<T2> m_argumentsOfType2; // ...
};
Or alternatively, I'd like to store the template argument types in a list, as to do some RTTI magic with it (?). But how to save them in a std::initializer_list member is also unclear to me.
Thanks for any help!
As you have already been hinted, the best way is to use a tuple:
template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2>
class MyClass {
std::tuple<std::vector<AcceptedTypes>...> vectors;
};
This is the only way to multiply the "fields" because you cannot magically make it spell up the field names. Another important thing may be to get some named access to them. I guess that what you're trying to achieve is to have multiple vectors with unique types, so you can have the following facility to "search" for the correct vector by its value type:
template <class T1, class T2>
struct SameType
{
static const bool value = false;
};
template<class T>
struct SameType<T, T>
{
static const bool value = true;
};
template <typename... Types>
class MyClass
{
public:
typedef std::tuple<vector<Types>...> vtype;
vtype vectors;
template<int N, typename T>
struct VectorOfType: SameType<T,
typename std::tuple_element<N, vtype>::type::value_type>
{ };
template <int N, class T, class Tuple,
bool Match = false> // this =false is only for clarity
struct MatchingField
{
static vector<T>& get(Tuple& tp)
{
// The "non-matching" version
return MatchingField<N+1, T, Tuple,
VectorOfType<N+1, T>::value>::get(tp);
}
};
template <int N, class T, class Tuple>
struct MatchingField<N, T, Tuple, true>
{
static vector<T>& get(Tuple& tp)
{
return std::get<N>(tp);
}
};
template <typename T>
vector<T>& access()
{
return MatchingField<0, T, vtype,
VectorOfType<0, T>::value>::get(vectors);
}
};
Here is the testcase so you can try it out:
int main( int argc, char** argv )
{
int twelf = 12.5;
typedef reference_wrapper<int> rint;
MyClass<float, rint> mc;
vector<rint>& i = mc.access<rint>();
i.push_back(twelf);
mc.access<float>().push_back(10.5);
cout << "Test:\n";
cout << "floats: " << mc.access<float>()[0] << endl;
cout << "ints: " << mc.access<rint>()[0] << endl;
//mc.access<double>();
return 0;
}
If you use any type that is not in the list of types you passed to specialize MyClass (see this commented-out access for double), you'll get a compile error, not too readable, but gcc at least points the correct place that has caused the problem and at least such an error message suggests the correct cause of the problem - here, for example, if you tried to do mc.access<double>():
error: ‘value’ is not a member of ‘MyClass<float, int>::VectorOfType<2, double>’
An alternate solution that doesn't use tuples is to use CRTP to create a class hierarchy where each base class is a specialization for one of the types:
#include <iostream>
#include <string>
template<class L, class... R> class My_class;
template<class L>
class My_class<L>
{
public:
protected:
L get()
{
return val;
}
void set(const L new_val)
{
val = new_val;
}
private:
L val;
};
template<class L, class... R>
class My_class : public My_class<L>, public My_class<R...>
{
public:
template<class T>
T Get()
{
return this->My_class<T>::get();
}
template<class T>
void Set(const T new_val)
{
this->My_class<T>::set(new_val);
}
};
int main(int, char**)
{
My_class<int, double, std::string> c;
c.Set<int>(4);
c.Set<double>(12.5);
c.Set<std::string>("Hello World");
std::cout << "int: " << c.Get<int>() << "\n";
std::cout << "double: " << c.Get<double>() << "\n";
std::cout << "string: " << c.Get<std::string>() << std::endl;
return 0;
}
One way to do such a thing, as mentioned in πάντα-ῥεῖ's comment is to use a tuple. What he didn't explain (probably to save you from yourself) is how that might look.
Here is an example:
using namespace std;
// define the abomination
template<typename...Types>
struct thing
{
thing(std::vector<Types>... args)
: _x { std::move(args)... }
{}
void print()
{
do_print_vectors(std::index_sequence_for<Types...>());
}
private:
template<std::size_t... Is>
void do_print_vectors(std::index_sequence<Is...>)
{
using swallow = int[];
(void)swallow{0, (print_one(std::get<Is>(_x)), 0)...};
}
template<class Vector>
void print_one(const Vector& v)
{
copy(begin(v), end(v), ostream_iterator<typename Vector::value_type>(cout, ","));
cout << endl;
}
private:
tuple<std::vector<Types>...> _x;
};
// test it
BOOST_AUTO_TEST_CASE(play_tuples)
{
thing<int, double, string> t {
{ 1, 2, 3, },
{ 1.1, 2.2, 3.3 },
{ "one"s, "two"s, "three"s }
};
t.print();
}
expected output:
1,2,3,
1.1,2.2,3.3,
one,two,three,
There is a proposal to allow this kind of expansion, with the intuitive syntax: P1858R1 Generalized pack declaration and usage. You can also initialize the members and access them by index. You can even support structured bindings by writing using... tuple_element = /*...*/:
template <typename... Ts>
class MyClass {
std::vector<Ts>... elems;
public:
using... tuple_element = std::vector<Ts>;
MyClass() = default;
explicit MyClass(std::vector<Ts>... args) noexcept
: elems(std::move(args))...
{
}
template <std::size_t I>
requires I < sizeof...(Ts)
auto& get() noexcept
{
return elems...[I];
}
template <std::size_t I>
requires I < sizeof...(Ts)
const auto& get() const
{
return elems...[I];
}
// ...
};
Then the class can be used like this:
using Vecs = MyClass<int, double>;
Vecs vecs{};
vecs.[0].resize(3, 42);
std::array<double, 4> arr{1.0, 2.0, 4.0, 8.0};
vecs.[1] = {arr.[:]};
// print the elements
// note the use of vecs.[:] and Vecs::[:]
(std::copy(vecs.[:].begin(), vecs.[:].end(),
std::ostream_iterator<Vecs::[:]>{std::cout, ' '},
std::cout << '\n'), ...);
Here is a less than perfectly efficient implementation using boost::variant:
template<typename ... Ts>
using variant_vector = boost::variant< std::vector<Ts>... >;
template<typename ...Ts>
struct MyClass {
using var_vec = variant_vector<Ts...>;
std::array<var_vec, sizeof...(Ts)> vecs;
};
we create a variant-vector that can hold one of a list of types in it. You have to use boost::variant to get at the contents (which means knowing the type of the contents, or writing a visitor).
We then store an array of these variant vectors, one per type.
Now, if your class only ever holds one type of data, you can do away with the array, and just have one member of type var_vec.
I cannot see why you'd want one vector of each type. I could see wanting a vector where each element is one of any type. That would be a vector<variant<Ts...>>, as opposed to the above variant<vector<Ts>...>.
variant<Ts...> is the boost union-with-type. any is the boost smart-void*. optional is the boost there-or-not.
template<class...Ts>
boost::optional<boost::variant<Ts...>> to_variant( boost::any );
may be a useful function, that takes an any and tries to convert it to any of the Ts... types in the variant, and returns it if it succeeds (and returns an empty optional if not).
Related
Suppose I have some class specialized for each enum type:
enum MyEnum {
EnumA = 0, EnumB, EnumSize
};
template <enum MyEnum>
class StaticEnumInfo {
};
template <>
class StaticEnumInfo<EnumA>{
typedef bool type;
const std::string name = "EnumA";
};
template <>
class StaticEnumInfo<EnumB>{
typedef int type;
const std::string name = "EnumB";
};
Is it possible to iterate over all names and print them?
I want to write something like:
for(MyEnum i = EnumA; i < EnumSize; ++i){
// Doesn't make sense, I know.
std::cout << StaticEnumInfo<i>::name << std::endl;
}
I know I can create one map somewhere else to solve this kind of mapping (for the strings, not the types...)
I don't have access to boost
Until proper expansion statements are available, you could always do this:
template <typename T, T... S, typename F>
constexpr void for_sequence(std::integer_sequence<T, S...>, F&& f) {
(static_cast<void>(f(std::integral_constant<T, S>{})), ...);
}
And use it like this:
for_sequence(
std::make_integer_sequence<int, EnumSize>{},
[&](auto i) {
constexpr auto index = static_cast<MyEnum>(int{i});
std::cout << StaticEnumInfo<index>::name << std::endl;
}
);
However be careful, as it will only work if all enum member are sequential.
Live example
Lets say I have a generic class Container that contains any type of tuple, and has a function template<typename T> T& get<T>(); that returns a reference to the element in the tuple. My very simple implementation looks like this:
template<typename... Ts>
class Container
{
std::tuple<Ts...> contents;
public:
Container(const Ts&... ts) : contents(ts...) {}
template <typename T>
T& get()
{
//TypeIndex is some meta-programming struct to find index of T in Ts
return std::get<TypeIndex<T, Ts...>::value>(contents);
}
};
Are there any good type erasure techniques to turn Container into a regular class without altering the get function signature? As in calling get<T>() without knowing the tuples full type list? Something like this:
Struct A { int x; }
Struct B { int y; }
Struct C { int z; }
int main()
{
Container container(A(), B()); //Underlying storage is a std::tuple<A, B>
A& a = container.get<A>(); //Doesn't know the tuples type list but assumes A is in there.
C& c = container.get<C>(); //C isn't in the tuples type list, crash program, which would be correct behavior.
}
boost::any is the usual go-to solution for these types of problems, but doesn't solve this particular problem because I would have to know the actual type of the underlying tuple to cast. Like if I tried to use it in the example above I would do boost::any_cast<std::tuple<A, B>> to get A, or B which isn't any use to me because I'm purposely trying to hide the tuple type list.
Edit: full definition of TypeIndex.
#include <type_traits>
template <typename T, typename... Ts>
struct TypeIndex;
template <typename T, typename... Ts>
struct TypeIndex<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
template <typename T, typename U, typename... Ts>
struct TypeIndex<T, U, Ts...> : std::integral_constant<std::size_t, 1 + TypeIndex<T, Ts...>::value> {};
Instead of hand written TypeIndex<T, Ts...>::value you can use typeid(T)::hash_code() and store data in a std::unordered_map<size_t, boost::any>.
std::tuple does not store information about underlying types. That information is encoded in tuple's type. So if your get method can't know the type of the tuple, then it can't get offset in it where the value is stored. So you have to revert to dynamic methods and having a map is the simpliest one.
A slightly more efficient solution than the ones proposed so far is to use std::tuple as the actual underlying storage, thus avoiding use of any or unordered_map
If we use the classic type-erasure pattern, we only need one dynamic allocation (plus whatever is required to copy the actual objects), or zero if you implement small buffer optimization.
We start by defining a base interface to access an element by type.
struct base
{
virtual ~base() {}
virtual void * get( std::type_info const & ) = 0;
};
We use void* instead of any to return a reference to the object, thus avoiding a copy and possibly a memory allocation.
The actual storage class is derived from base, and templated on the arguments it can contain:
template<class ... Ts>
struct impl : base
{
template<class ... Us>
impl(Us && ... us) : data_(std::forward<Us>(us) ... )
{
//Maybe check for duplicated types and throw.
}
virtual void * get( std::type_info const & ti )
{
return get_helper( ti, std::index_sequence_for<Ts...>() );
}
template<std::size_t ... Indices>
void* get_helper( std::type_info const & ti, std::index_sequence<Indices...> )
{
//If you know that only one element of a certain type is available, you can refactor this to avoid comparing all the type_infos
const bool valid[] = { (ti == typeid(Ts)) ... };
const std::size_t c = std::count( std::begin(valid), std::end(valid), true );
if ( c != 1 )
{
throw std::runtime_error(""); // something here
}
// Pack the addresses of all the elements in an array
void * result[] = { static_cast<void*>(& std::get<Indices>(data_) ) ... };
// Get the index of the element we want
const int which = std::find( std::begin(valid), std::end(valid), true ) - std::begin(valid);
return result[which];
}
std::tuple<Ts ... > data_;
};
Now we only have to wrap this in a type-safe wrapper:
class any_tuple
{
public:
any_tuple() = default; // allow empty state
template<class ... Us>
any_tuple(Us && ... us) :
m_( new impl< std::remove_reference_t< std::remove_cv_t<Us> > ... >( std::forward<Us>(us) ... ) )
{}
template<class T>
T& get()
{
if ( !m_ )
{
throw std::runtime_error(""); // something
}
return *reinterpret_cast<T*>( m_->get( typeid(T) ) );
}
template<class T>
const T& get() const
{
return const_cast<any_tuple&>(*this).get<T>();
}
bool valid() const { return bool(m_); }
private:
std::unique_ptr< base > m_; //Possibly use small buffer optimization
};
Check it live.
This can be extended further in many ways, for instance you can add a constructor that takes an actual tuple, you can access by index and pack the value in a std::any, etc.
#include <iostream>
struct tuple_base {
virtual ~tuple_base() {}
};
template <typename T>
struct leaf : virtual tuple_base {
leaf(T const & t) : value(t) {}
virtual ~leaf() {}
T value;
};
template <typename ... T>
struct tuple : public leaf<T> ... {
template <typename ... U>
tuple(U && ... u) : leaf<T>{static_cast<U&&>(u)} ... {}
};
struct container {
tuple_base* erased_value;
template <typename T>
T & get() {
return dynamic_cast<leaf<T>*>(erased_value)->value;
}
};
int main() {
container c{new tuple<int, float, char>{1, 1.23f, 'c'}};
std::cout << c.get<float>() << std::endl;
}
The key is that you must know more information about the structure of the tuple type. It is not possible to extract information from a type erased arbitrary tuple implementation using only a single type which it contains. This is more of a proof of concept, and you would probably be better off using something else, though it is the solution to what you asked.
If you're ok with using boost::any, you could use a vector or unordered_map of them. Here's a version implemented with unordered_map:
class Container
{
public:
template<typename... Ts>
Container(std::tuple<Ts...>&& t)
{
tuple_assign(std::move(t), data, std::index_sequence_for<Ts...>{});
}
template<typename T>
T get()
{
auto it = data.find(typeid(T));
if(it == data.cend()) {
throw boost::bad_any_cast{};
} else {
return boost::any_cast<T>(it->second);
}
}
private:
std::unordered_map<std::type_index, boost::any> data;
};
And then you could write almost as in your request. I changed the constructor to accept a tuple to avoid a host of sfinae code to prevent overridding copy/move constructors, but you can do this if you so wish.
Container c(std::make_tuple(1, 1.5, A{42}));
try {
std::cout << "int: " << c.get<int>() << '\n';
std::cout << "double: " << c.get<double>() << '\n';
std::cout << "A: " << c.get<A>().val << '\n';
c.get<A&>().val = 0;
std::cout << "A: " << c.get<A>().val << '\n';
std::cout << "B: " << c.get<B>().val << '\n'; // error
} catch (boost::bad_any_cast const& ex) {
std::cout << "exception: " << ex.what() << '\n';
}
live demo
You could also instruct your Container to commit std::terminate() instead of throwing an exception.
Consider the following:
template<typename T>
struct S
{
typedef M< &T::foo > MT;
}
This would work for:
S<Widget> SW;
where Widget::foo() is some function
How would I modify the definition of struct S to allow the following instead:
S<Widget*> SWP;
What you need is the following type transformation.
given T, return T
given T *, return T
It so happens that the standard library already has implemented this for us in std::remove_pointer (though it's not hard to do yourself).
With this, you can then write
using object_type = std::remove_pointer_t<T>;
using return_type = /* whatever foo returns */;
using MT = M<object_type, return_type, &object_type::foo>;
Regarding your comment that you also want to work with smart pointers, we have to re-define the type transformation.
given a smart pointer type smart_ptr<T>, return smart_ptr<T>::element_type, which should be T
given a pointer type T *, return T
otherwise, given T, return T itself
For this, we'll have to code our own meta-function. At least, I'm not aware of anything in the standard library that would help here.
We start by defining the primary template (the “otherwise” case).
template <typename T, typename = void>
struct unwrap_obect_type { using type = T; };
The second (anonymous) type parameter that is defaulted to void will be of use later.
For (raw) pointers, we provide the following partial specialization.
template <typename T>
struct unwrap_obect_type<T *, void> { using type = T; };
If we'd stop here, we'd basically get std::remove_pointer. But we'll add an additional partial specialization for smart pointers. Of course, we'll first have to define what a “smart pointer” is. For the purpose of this example, we'll treat every type with a nested typedef named element_type as a smart pointer. Adjust this definition as you see fit.
template <typename T>
struct unwrap_obect_type
<
T,
std::conditional_t<false, typename T::element_type, void>
>
{
using type = typename T::element_type;
};
The second type parameter std::conditional_t<false, typename T::element_type, void> is a convoluted way to simulate std::void_t in C++14. The idea is that we have the following partial type function.
given a type T with a nested typedef named element_type, return void
otherwise, trigger a substitution failure
Therefore, if we are dealing with a smart pointer, we'll get a better match than the primary template and otherwise, SFINAE will remove this partial specialization from further consideration.
Here is a working example. T.C. has suggested using std::mem_fn to invoke the member function. This makes the code a lot cleaner than my initial example.
#include <cstddef>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <utility>
template <typename ObjT, typename RetT, RetT (ObjT::*Pmf)() const noexcept>
struct M
{
template <typename ThingT>
static RetT
call(ThingT&& thing) noexcept
{
auto wrapper = std::mem_fn(Pmf);
return wrapper(std::forward<ThingT>(thing));
}
};
template <typename T, typename = void>
struct unwrap_obect_type { using type = T; };
template <typename T>
struct unwrap_obect_type<T *, void> { using type = T; };
template <typename T>
struct unwrap_obect_type<T, std::conditional_t<false, typename T::element_type, void>> { using type = typename T::element_type; };
template <typename T>
struct S
{
template <typename ThingT>
void
operator()(ThingT&& thing) const noexcept
{
using object_type = typename unwrap_obect_type<T>::type;
using id_caller_type = M<object_type, int, &object_type::id>;
using name_caller_type = M<object_type, const std::string&, &object_type::name>;
using name_length_caller_type = M<object_type, std::size_t, &object_type::name_length>;
std::cout << "id: " << id_caller_type::call(thing) << "\n";
std::cout << "name: " << name_caller_type::call(thing) << "\n";
std::cout << "name_length: " << name_length_caller_type::call(thing) << "\n";
}
};
class employee final
{
private:
int id_ {};
std::string name_ {};
public:
employee(int id, std::string name) : id_ {id}, name_ {std::move(name)}
{
}
int id() const noexcept { return this->id_; }
const std::string& name() const noexcept { return this->name_; }
std::size_t name_length() const noexcept { return this->name_.length(); }
};
int
main()
{
const auto bob = std::make_shared<employee>(100, "Smart Bob");
const auto s_object = S<employee> {};
const auto s_pointer = S<employee *> {};
const auto s_smart_pointer = S<std::shared_ptr<employee>> {};
s_object(*bob);
std::cout << "\n";
s_pointer(bob.get());
std::cout << "\n";
s_smart_pointer(bob);
}
So suppose, that I have got a class, that contains functional object and in the constructor call I pass arguments, that are to be passed to the functional object some time later. Something like:
class Binder{
public:
Binder(functional_object, listOfParameters);
callFunctionalObject(); // calls functional object with given list of parameters
};
Before C++11 I could not use Variadic templates, so one would do:
struct none{};
template <typename T1, typename T2=none, typename T3=none>
class Binder{
public:
Binder(T1 functionalObject, T2 arg1=none(), T3arg3=none());
void callFunctionalObject();
private:
T1 m_functionalObject;
T2 m_arg1;
T3 m_arg2;
};
Where callFunctionalobject could be implemented as follows:
template<typename T1, typename T2, typename T3>
void Binder<T1,T2,T3>::callFunctionalObject(){
callImpl(m_functionalObject, m_arg1, m_arg2);
}
and callImpl would be overloaded to recognize objects of type none to pass proper amount of arguments to the functional object.
Now switching to C++11 I do not know how to implement the fact, that in private section I have got members, to which I have an direct access.
Could anyone explain me the way I can do the same using C++11 or C++14?
You should store a std::function and a std::tuple and then call the function on the tuple.
Here a working C++14 solution
#include <iostream>
#include <functional>
template<typename T1, typename ...T>
class Binder
{
public:
Binder(std::function<T1(T...)> f, std::tuple<T...> t) : m_functional_obj(f), m_parameters(t) {}
template<std::size_t ...I>
T1 callImpl(std::index_sequence<I...>)
{
return m_functional_obj(std::get<I>(m_parameters)...);
}
T1 callFunctionalObject()
{
return callImpl(std::index_sequence_for<T...>{});
}
private:
std::function<T1(T...)> m_functional_obj;
std::tuple<T...> m_parameters;
};
int test(int i)
{
std::cout << "test(" << i << ")" << std::endl;
return i + 1;
}
int main()
{
Binder<int,int> bibi(test, std::make_tuple<int>(2));
auto res = bibi.callFunctionalObject();
std::cout << "res is " << res << std::endl;
}
Live code
My example:
// Indices
template <std::size_t... Is>
struct Indices {};
template <std::size_t N, std::size_t... Is>
struct BuildIndices : BuildIndices <N - 1, N - 1, Is...> {};
template <std::size_t... Is>
struct BuildIndices<0, Is...> : Indices < Is... > {};
template<class FuncObject, class ... T>
class Binder
{
public:
Binder(FuncObject funcObject, T... args)
: m_funcObject(funcObject), m_arguments(std::make_tuple(args...))
{
}
void Call()
{
DoCall(BuildIndices<sizeof ... (T)> {});
}
private:
template<size_t... Ind>
void DoCall(Indices<Ind...>)
{
return m_funcObject(std::get<Ind>(m_arguments)...);
}
FuncObject m_funcObject;
std::tuple<T...> m_arguments;
};
void Foo(int, char)
{
}
int main()
{
Binder<void(*)(int, char), int, char> f(Foo, 1, 'd');
f.Call();
return 0;
}
The simplest way is to store an std::function object with already-set arguments using std::bind:
class Binder{
public:
template <typename T1, typename... T2>
Binder(T1 functionalObject, T2... args) : f(std::bind(functionalObject, args...)) {}
void callFunctionalObject() { f(); }
private:
std::function<void()> f;
};
void foo(int n, std::string s) {
std::cout << n << " " << s << std::endl;
}
int main()
{
Binder b(foo, 42, "test");
b.callFunctionalObject();
}
If you need something more advanced, then you might want to store the function arguments in and std::tuple and then use some template magic to unwrap it, but please specify what exactly do you need in the question.
P.S. See also "unpacking" a tuple to call a matching function pointer
I have a class like this:
template<typename ... TTypes>
class Composite {
public:
std::tuple<TTypes...> &getRefValues() { return values; }
private:
std::tuple<TTypes...> values;
};
Can I define std::get for my class Composite? It should basically call the already defined std::get for the private tuple values.
I was able to implement a customized get function when the return type is known (e.g. for an int array member) but I don't know how to realize get when the return type can be an arbitrary type (depending on the components' type of the tuple values)?
You may do:
template <std::size_t I, typename... Ts>
auto get(Composite<Ts...>& composite)
-> decltype(std::get<I>(composite.getRefValues()))
{
return std::get<I>(composite.getRefValues());
}
Note: In C++14, you may omit the -> decltype(..) part.
For completeness, here is my solution. Thanks everyone:
template<typename ... TTypes>
class Composite {
public:
Composite(TTypes... t) {
std::tuple<TTypes...> tuple(t...);
values = tuple;
}
std::tuple<TTypes...> &getRefValues() { return values; }
private:
std::tuple<TTypes...> values;
};
namespace std {
template<size_t I, typename ... TTypes>
auto get(Composite<TTypes ...> &t) -> typename std::tuple_element<I, std::tuple<TTypes...>>::type {
return std::get<I>(t.getRefValues());
}
}
int main() {
Composite<int, char, double> c(13, 'c', 13.5);
std::cout << std::get<0>(c) << std::endl;
std::cout << std::get<1>(c) << std::endl;
std::cout << std::get<2>(c) << std::endl;
return 0;
}