Create instances from variadic templates - c++

I'm trying to come up with a class that allows multiple types to be created via variadic template arguments, but I get errors during compilation:
http://ideone.com/nDWBET
#include <list>
#include <memory>
struct IBaseType
{
};
class Type1 : public IBaseType
{
};
class Type2 : public IBaseType
{
};
template <typename... T>
class CreateTypes
{
public:
CreateTypes()
{
[](...){ }((m_types.push_back(std::unique_ptr<T>(new T())))...);
}
private:
std::list<std::unique_ptr<IBaseType>> m_types;
};
int main()
{
CreateTypes<Type1, Type2> createTypes;
return 0;
}
prog.cpp: In instantiation of ‘CreateTypes::CreateTypes() [with T = {Type1, Type2}]’:
prog.cpp:31:28: required from here
prog.cpp:22:9: error: invalid use of void expression
What's the solution for this? Or is there an alternative approach that I can take?

Problem here is, that push_back returns void. You can try to use insert
[](...) { }((m_types.insert(m_types.end(), std::unique_ptr<T>(new T())), 0)...);
from comments:
with 0 push_back will work too.
[](...) { }((m_types.push_back(std::unique_ptr<T>(new T())), 0)...);

ForEveR and Xeo gave me the answers I was looking for, but I had to adapt their solutions slightly as Clang wouldn't execute the code of the empty lambda (I assume it was optimised away, even in debug). Here's my final solution (which incorporates a runtime check to ensure the right number of types is always created):
template <typename... Types>
struct VariadicTemplateCount
{
static const size_t value = sizeof...(Types);
};
// ..............
CreateTypes()
{
struct ShutTheCompiler
{
static void Up(const int[])
{
}
};
const int creation[] = {0, (m_types.push_back(std::unique_ptr<T>(new T())), 0)... };
ShutTheCompiler::Up(creation);
ASSERT(m_types.size() == VariadicTemplateCount<Types...>::value);
}

Related

Passing different datatypes via a loop

Lets say I have a function
template<typename T>
some_function(T a){
// some operations..
}
I have a huge list of classes who objects i want to pass to the function one by one(Don't ask me why I'm forced to have it like that.)
class type1{ //.. whateever is necessary here...
};
class type2{ //.. whateever is necessary here...
};
class type3{ //.. whateever is necessary here...
};
class type4{ //.. whateever is necessary here...
};
.
.
and so on
Is there a way I can instantiate an object of each data and pass it to the function within a loop, rather than type one by one it manually.
(It would be better if the instantiation happens within the loop so that the object is local for every loop).
Any way to approach this problem other than typing it manually is welcome.
EDIT:
Since there were questions in the comments. Let me elaborate on the type of algorithm I am looking for.
Step 1: Pick a class my_class in [type1,type2,...,typeN]
Step 2: Instantiate an object of that class my_class object
Step 3: Pass it to the function some_function(object)
Step 4: Go to step 1 and pick the next class.
I hope I made things clear.
EDIT 2: I use c++11 . But I don't mind switching if it is needed
Let me elaborate on the type of algorithm I am looking for.
Step 1: Pick a class my_class in [type1,type2,...,typeN]
Step 2: Instantiate an object of that class my_class object
Step 3: Pass it to the function some_function(object)
Step 4: Go to step 1 and pick the next class.
If you can use C++11 or newer, and if you can pass immediately the object instantiated to some_function(), you can simulate a loop with a variadic template type list as follows
template <typename ... Ts>
void repeatOverTypes ()
{
using unused=int[];
(void)unused { 0, (some_function(Ts{}), 0)... };
}
The following is a full compiling example
#include <iostream>
class type_1 { };
class type_2 { };
class type_3 { };
class type_4 { };
template <typename T>
void some_function (T a)
{ }
template <typename ... Ts>
void repeatOverTypes ()
{
using unused=int[];
(void)unused { 0, (some_function(Ts{}), 0)... };
}
int main ()
{
repeatOverTypes<type_1, type_2, type_3, type_4>();
}
If you can use C++17, using folding repeatOverTypes() become simply
template <typename ... Ts>
void repeatOverTypes ()
{ (some_function(Ts{}), ...); }
-- EDIT --
The OP say
I overlooked an important detail while trying to simplify the problem. I need to pass the objects by reference. So the Ts{} won't work ? What can i do ?
I see... well, I suppose you can (1) create the Ts{} object and store they in a container (a std::tuple seems to me an obvious container) and (2) pass to some_function() the values extracted from the tuple.
The point (1) is simple
std::tuple<Ts...> t { Ts{}... };
The point (2) heavily depend from the list of type (there are repetitions in "type1,type2,...,typeN" ?) and the exact language.
If all types in the list are different and you can use C++14, you can access the tuple values trough std::get<Ts>(t); so the function can be written
template <typename ... Ts>
void repeatOverTypes ()
{
using unused=int[];
std::tuple<Ts...> t { Ts{}... };
(void)unused { 0, (some_function(std::get<Ts>(t)), 0)... };
}
If there are repetitions, you have to access value via integer index, so you have to create a list of index and pass they to an helper function; something like
template <typename T, std::size_t ... Is>
void rotH (T & t, std::index_sequence<Is...> const &)
{
using unused=int[];
(void)unused { 0, (some_function(std::get<Is>(t)), 0)... };
}
template <typename ... Ts>
void repeatOverTypes ()
{
std::tuple<Ts...> t { Ts{}... };
rotH(t, std::make_index_sequence<sizeof...(Ts)>{});
}
Unfortunately std::index_sequence and std::make_index_sequence are introduced in C++14 so, in C++11, you have to simulate they in some way.
As usual in C++17 is simpler; if you are sure (but really, really sure) that types are all different, the function is simply
template <typename ... Ts>
void repeatOverTypes ()
{
std::tuple<Ts...> t { Ts{}... };
(some_function(std::get<Ts>(t)), ...);
}
In case of types collision, with integer sequence,
template <typename T, std::size_t ... Is>
void rotH (T & t, std::index_sequence<Is...> const &)
{ (some_function(std::get<Is>(t)), ...); }
template <typename ... Ts>
void repeatOverTypes ()
{
std::tuple<Ts...> t { Ts{}... };
rotH(t, std::make_index_sequence<sizeof...(Ts)>{});
}
I have a huge list of classes who objects i want to pass to the function one by one
As you seem to need handling many types and avoid to type them out hardcoded in a single place of your code (as provided in this answer), you should consider using dynamic polymorphism, interfaces and self-registering classes rather.
This is a well known technique when a uniform set of operations needs to be done over a lot of specific class types. Many unit testing frameworks use that in order to avoid that additional test cases need to be added at a central place, but just within the translation unit where they're defined.
Here's a sketch (untested) how to implement such:
Provide an interface to describe what needs to be done in some_function() uniquely:
struct IMyInterface {
virtual ~IMyInterface() {}
virtual void WhatNeedsToBeDone() = 0;
virtual int WhatNeedsToBeKnown() const = 0;
};
void some_function(IMyInterface* intf) {
if(intf->WhatNeedsToBeKnown() == 1) {
intf->WhatNeedsToBeDone();
}
}
Provide a singleton registrar keeping a map of functions to create your classes:
class MyRegistrar {
MyRegistrar() {};
using FactoryFunction = std::function<std::unique_ptr<IMyInterface> ()>;
std::map<std::string, FactoryFunction> classFactories;
public:
static MyRegistrar& ClassRegistry() {
static MyRegistrar theRegistrar;
return theRegistrar;
};
template<typename T>
void registerClassFactory(
FactoryFunction factory) {
classFactories[typeid(T).name()] = factory;
};
template<typename T>
std::unique_ptr<IMyInterface> createInstance() {
return classFactories[typeid(T).name()]();
}
template<typename T>
const FactoryFunction& factory() const {
return classFactories[typeid(T).name()];
}
std::vector<FactoryFunction> factories() const {
std::vector<FactoryFunction> result;
for(auto& factory : classFactories) {
result.push_back(factory);
}
return result;
}
};
also provide a registration helper to make it easier registering the types with the global registrar
template<typename T>
struct RegistrationHelper {
RegistrationHelper(
std::function<std::unique_ptr<IMyInterface> ()> factoryFunc =
[](){ return std::make_unique<T>(); }) {
MyRegistrar::ClassRegistry().registerClassFactory<T>(factoryFunc);
}
};
In your specific types you can use that like
class type1 : public IMyInterface {
static RegistrationHelper<type1> reghelper;
public:
void WhatNeedsToBeDone() override {}
int WhatNeedsToBeKnown() const override { return 0; };
};
RegistrationHelper<type1> type1::reghelper;
You can also specialize to deviate from the default factory function:
enum Color { Red, Green };
class type1 : public IMyInterface {
static RegistrationHelper<type1> reghelper;
Color color_;
public:
type1(Color color) : color_(color) {}
void WhatNeedsToBeDone() override {}
int WhatNeedsToBeKnown() const override { return 0; };
};
RegistrationHelper<type1> type1::reghelper(
[](){ return std::make_unique<type1>(condition? Green : Red);
} -> std::function<std::unique_ptr<IMyInterface> ()>
);
To realize your iteration over all classes you can use
for(auto factory : MyRegistrar::ClassRegistry().factories()) {
std::unique_ptr<IMyInterface> intf = factory();
some_function(intf.get());
}

Using constexpr-if in a generic lambda to determine type of a parameter

I have the following problem: I have a class hierarchy with a base class and two sub-classes. I have implemented a resolve_type function that accepts an instance of the base class and a generic lambda (or similar). The function resolves its type and passes it to the lambda. Inside this lambda, I’d like to check the column’s type within a constexpr-if condition in order to exclude certain types. I have tried to do this with constexpr member functions in the sub-classes, which unfortunately didn’t work.
Code:
class AbstractColumn
{
};
template <typename Type>
class DataColumn : public AbstractColumn
{
public:
constexpr bool is_reference_column() { return false; }
void foo() {}
};
class ReferenceColumn : public AbstractColumn
{
public:
constexpr bool is_reference_column() { return true; }
};
template <typename Functor>
resolve_type(const AbstractColumn & col, const Functor & func);
Usage:
AbstractColumn & col = ...;
...
resolve_type(col, [] (const auto & col)
{
// col could be ReferenceColumn, DataColumn<int>, DataColumn<float>, DataColumn<double>, DataColumn<std::string> ...
if constexpr (!col.is_reference_column()) {
col.foo();
}
});
Compiler Error:
Apple LLVM version 8.1.0 (clang-802.0.42)
error: constexpr if condition is not a constant expression
if constexpr (col.is_reference_column()) {
I know that I could use decltype to get the type and then continue using some template magic, but I had hoped to find something that is a bit more readable. My project already uses boost and its hana library, so solutions could also use these two. Does anyone have any ideas?
Use a static constexpr method instead.
It follows a minimal, working example:
#include<type_traits>
struct A {
static constexpr bool is_reference_column() { return false; }
};
int main() {
[](const auto &col) {
if constexpr(std::decay_t<decltype(col)>::is_reference_column()) {
// ...
}
}(A{});
}
Or just inherits from std::true_type/std::false_type:
#include<type_traits>
struct A: std::true_type {};
int main() {
[](const auto &col) {
if constexpr(std::decay_t<decltype(col)>::value) {
// ...
}
}(A{});
}
Or use an intermediate class template instead of redefining continuously is_reference_column:
#include<type_traits>
template<bool refcol>
struct I {
static constexpr bool is_reference_column = refcol;
};
struct A: I<true> {};
int main() {
[](const auto &col) {
if constexpr(std::decay_t<decltype(col)>::is_reference_column) {
// ...
}
}(A{});
}
Plenty of alternatives, but you cannot simply use col in a constant expression just because you declared it as a const reference. col is a runtime instance of a type T, there is no chance you can use it at compile-time as you tried to do.
I think you're overthinking this. You don't need a member function to just identify the type of the object. You can just look at the type. So at a first go, that's simply:
resolve_type(col, [] (const auto& col)
{
if constexpr (hana::typeid_(col) == hana::type_c<ReferenceColumn>) {
col.foo();
}
});
Even simpler would just be to create an overload set and just use overload resolution. There are several implementations of such a mechanism floating around here, it's especially straightforward to write in C++17. Using that:
resolve_type(col, overload(
[](ReferenceColumn const& ref){
ref.foo();
},
[](auto const& other) {
}));

Generic vector of templates

For me generic vectors of templates are vector that can take template with any argument list. Like this
vector<Foo<?>> foos;
foos.push_back(Foo<int>(5));
foos.push_back(Foo<Bar>(Bar()));
foos.push_back(Foo<string>("bar"));
EDIT:
This is why I need this
#ifndef EVENT_DISPATCHER_H
#define EVENT_DISPATCHER_H
// #include <boost/signals2.hpp>
#include <string>
#include <vector>
#include <functional>
#include <map>
namespace Whitedrop {
template <typename... T> class EventDispatcher {
public:
EventDispatcher(std::string eventID)
{
}
void on(std::function<void(T...)> callback)
{
mCallbacks.push_back(callback);
}
void trigger(T&... args)
{
for (auto f : mCallbacks)
f(args...);
}
protected:
std::vector<std::function<void(T...)>> mCallbacks;
};
std::map<std::string, EventDispatcher<?> > dispatchers; // HERE <--------
template<typename... T> void registerListener(std::string eventID, std::function<void(T...)> callback)
{
if (!dispatchers.count(eventID))
{
dispatchers[eventID] = new EventDispatcher<T...>(eventID);
return;
}
dispatchers.find(eventID)->second.on(callback);
//std::shared_ptr<Chunk> chunk = mChunks.find(pos)->second;
}
template<typename... T> void invokeListener(std::string eventID, T... args)
{
if (!dispatchers.count(eventID))
{
return;
}
dispatchers.find(eventID)->second->trigger(args...);
}
};
#endif
SInce it seems not possible, how can I resolve my issue?
No, that is not possible. Class templates are templates, not types. The std::vector template requires a type as its first argument, not a template.
You can use class templates to produce types, but you have to choose one particular type for each instantiation of the std::vector template.
More generally, the nature of a template parameter tells you what kind of argument you can use. In C++ there are three "ontological tiers": values ("things that have types), types ("things that are types), and templates ("things that make any of the three"). Each can appear as a template parameter:
template < int A // Value (int prvalue)
, typename B, // Type
, template <typename> class C // Template
> struct Foo {};
Foo<10, double, std::allocator> foo;
// A B C
Simple answer is no.
The compiler needs to figure out types and sizes.
EDIT
Use inheritance
Eg
class Event {
private:
std::string m_id;
public:
Event(std:string &id) : m_id(id) { }
std:string EveentId() const { return m_id;}
virtual void DoEvent() = 0;
};
class MyEvent : Event {
public:
MyEvent() : Event("MyEvent") { }
DoEvent() { std::cout << "MyEvent" << std::endl;
};
Then have a list of events
i.e.
std::vector<std::shard_ptr<Event>> events;
events.push_back<std::make_shared<MyEvent>());
events[0]->DoEvent();
std::vector is a homogeneous container, which means it can only contain one type. Note that Foo<> is a family of types not a single type, the type of std::vector is different depending on the template parameter.
Now, you can achieve what you want using two methods I can think off, the first is by erasing the type, for example you can use std::vector<boost::any>, but note that it completely erases the type (the type info is lost), and is not a compile time operation.
The second way is using a tuple, this is a compile time fixed-size container, which means you can't add new elements at runtime, because the type of each object is determined at compile time.

C++ metaprogramming issue/challenge to generate a type based on it function calls

I have a C++ problem. I want to generate a type based on the type arguments passed to a templated function of it.
Let me illustrate it.
class A {
template<class B> M() { }
void Z() {
// NOTE: Here I want to call to X on each type that was feed it to M.
X<N1>();
X<N1>();
...
X<NN>();
}
template<class B> X() { }
};
For example
A a;
a.M<int>();
a.M<double>();
then a.Z() executes ...
X<int>();
X<double>();
Another example to take into account unique types
A a;
a.M<int>();
a.M<int>();
a.M<double>();
a.M<double>();
then a.Z() will still executes ...
X<int>();
X<double>();
Note that I am generating the type A based on the calls to M.
OK! I think that for that class A that's conceptually impossible because A is not templated type and then it can not vary in that way, In fact that's not possible for any type in C++ (I think). But I want you to get the idea.
I am looking forward for a way to confront this problem using meta-programming, but any advice or solution or reference is welcome.
No metaprogramming needed.
class A {
using XPtr = void (A::*)();
std::vector<XPtr> x_calls;
std::set<std::type_index> x_types;
template <typename B> void X() { ... }
public:
template <typename B> void M() {
bool is_new = x_types.insert(std::type_index(typeid(B))).second;
if (is_new)
x_calls.push_back(&A::X<B>);
...
}
void Z() {
for (auto&& ptr : x_calls) {
(this->*ptr)();
}
}
};
First off, I think you're interface isn't really MPL. To be MPL you'd call it more like typedef MyType mpl::vector<int, double> and then find a way to build a type that called X<...> for each type. However...
#include <iostream>
#include <typeinfo>
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;
template< typename T>
void X() {
cout<<typeid(T).name()<<endl;
}
struct A {
vector< function<void(void)> > callbacks;
void z() {
for( auto a : callbacks ) a();
}
template<typename T>
void M() {
callbacks.push_back( [](){ X<T>();} );
}
};
int main() {
A a;
a.M<int>();
a.M<double>();
a.z();
return 0;
}
does what you want.
$ g++ --std=c++11 && ./a.out
i
d
Ss
See it live
You can achieve similar functionality using boost::fusion::set and boost::mpl.
class A {
struct functoid {
template<typename T>
void operator(T t)
{
/* do something */
}
}
template<class B> M() {
boost::mpl::for_each<B>(functoid());
}
}
A a;
a.template M<boost::fusion::set<int, double, ...>>();
But, in this case, you need to know the actual types, or, register some callback in operator().

Inserting a variadic argument list into a vector?

Forgive me if this has been answered already, as I couldn't find it...
Basically I have an object that needs to take a variadic argument list in it's constructor and store the arguments in a vector. How do I initialize a vector from a the arguments of a variadic constructor?
class GenericNode {
public:
GenericNode(GenericNode*... inputs) {
/* Something like... */
// inputs_.push_back(inputs)...;
}
private:
std::vector<GenericNode*> inputs_;
};
The best thing would be to use an initializer list
#include <initializer_list>
#include <vector>
class GenericNode {
public:
GenericNode(std::initializer_list<GenericNode*> inputs)
:inputs_(inputs) {} //well that's easy
private:
std::vector<GenericNode*> inputs_;
};
int main() {
GenericNode* ptr;
GenericNode node{ptr, ptr, ptr, ptr};
} //compilation at http://stacked-crooked.com/view?id=88ebac6a4490915fc4bc608765ba2b6c
The closest to what you already have, using C++11 is to use the vector's initializer_list:
template<class ...Ts>
GenericNode(Ts... inputs)
:inputs_{inputs...} {} //well that's easy too
//compilation at http://stacked-crooked.com/view?id=2f7514b33401c51d33677bbff358f8ae
And here's a C++11 version with no initializer_lists at all. It's ugly, and complicated, and requires features missing from many compilers. Use the initializer list
template<class T>
using Alias = T;
class GenericNode {
public:
template<class ...Ts>
GenericNode(Ts... inputs) { //SFINAE might be appropriate
using ptr = GenericNode*;
Alias<char[]>{( //first part of magic unpacker
inputs_.push_back(ptr(inputs))
,'0')...,'0'}; //second part of magic unpacker
}
private:
std::vector<GenericNode*> inputs_;
};
int main() {
GenericNode* ptr;
GenericNode node(ptr, ptr, ptr, ptr);
} //compilation at http://stacked-crooked.com/view?id=57c533692166fb222adf5f837891e1f9
//thanks to R. Martinho Fernandes for helping me get it to compile
Unrelated to everything, I don't know if those are owning pointers or not. If they are, use std::unique_ptr instead.
// inputs_.push_back(inputs)...;
This doesn't work because you can't expand a parameter pack as a statement, only in certain contexts such as a function argument list or initializer-list.
Also your constructor signature is wrong, if you're trying to write a variadic template it needs to be a template!
Once you write your constructor signature correctly the answer is easy, just construct the vector with the pack expansion:
#include <vector>
class GenericNode
{
public:
template<typename... T>
GenericNode(T*... inputs) : inputs_{ inputs... }
{ }
private:
std::vector<GenericNode*> inputs_;
};
(You could instead have set it in the constructor body with:
inputs_ = { inputs... };
but the cool kids use member initializers not assignment in the constructor body.)
The downside of this solution is that the template constructor accepts any type of pointer arguments, but will then give an error when trying to construct the vector if the arguments aren't convertible to GenericNode*. You could constrain the template to only accept GenericNode pointers, but that's what happens automatically if you do what the other answers suggest and make the constructor take a std::initializer_list<GenericNode*>, and then you don't need any ugly enable_if SFINAE tricks.
You can't use a variadic argument list unless it's a template, you can, as stated, use a initializer_list like this:
class GenericNode {
public:
GenericNode(std::initializer_list<GenericNode*> inputs) : inputs_(inputs)
{
}
private:
std::vector<GenericNode*> inputs_;
};
template <class ... T>
GenericNode* foo(T ... t)
{
return new GenericNode({t...});
}
class Blob
{
std::vector<std::string> _v;
public:
template<typename... Args>
Blob(Args&&... args)
: _v(std::forward<Args>(args)...)
{ }
};
int main(void)
{
const char * shapes[3] = { "Circle", "Triangle", "Square" };
Blob b1(5, "C++ Truths");
Blob b2(shapes, shapes+3);
}
Example from C++11 Truths looks simple enough...;)
Not a complete solution but might give you some ideas.
Another way to do it:
#include <iostream>
#include <vector>
using std::vector;
template <typename T>
void variadic_vector_emplace(vector<T>&) {}
template <typename T, typename First, typename... Args>
void variadic_vector_emplace(vector<T>& v, First&& first, Args&&... args)
{
v.emplace_back(std::forward<First>(first));
variadic_vector_emplace(v, std::forward<Args>(args)...);
}
struct my_struct
{
template <typename... Args>
my_struct(Args&&... args)
{
variadic_vector_emplace(_data, std::forward<Args>(args)...);
}
vector<int>& data() { return _data; }
private:
vector<int> _data;
};
int main()
{
my_struct my(5, 6, 7, 8);
for(int i : my.data())
std::cout << i << std::endl;
}
I recently wrote the following function that takes a string with
{1} , {2} , {3} ... in it and substitutes the argument list. I ran in to the same problem until I decided to let the compiler work it out for itself with the auto keyword.
#include <string>
#include <vector>
using std::string;
using std::vector;
template<typename S, typename... Args>
string interpolate( const S& orig , const Args&... args)
{
string out(orig);
auto va = {args...};
vector<string> v{va};
size_t i = 1;
for( string s: v)
{
string is = std::to_string(i);
string t = "{" + is + "}";
try
{
auto pos = out.find(t);
if(pos != out.npos)
{
out.erase(pos, t.length());
out.insert( pos, s);
}
i++;
}
catch( std::exception& e)
{
std::cerr << e.what() << std::endl;
}
} // for
return out;
}
Apparently that is good enough as long as the types line up correctly.
In this case I am using only std::string throughout.
I think this is an elegant technique, but it may have drawbacks.
Note: If the element-type of a vector is not copy-initializable (it is in OP post), the std::initializer list route will not work.
You can still use a variadic unpack statement (post C++ 17):
(inputs_.emplace_back(std::move(args)), ...);