Assume the following template construction:
enum class ENUM {SINGLE, PAIR};
// General data type
template<ENUM T, class U>class Data;
// Partially specialized for single objects
template<class U>Data<ENUM::SINGLE, U> : public U {
// Forward Constructors, ...
};
// Partially specialized for pairs of objects
template<class U>Data<ENUM::PAIR, U> : public std::pair<U,U> {
// Forward Constructors, ...
};
In my code I want to be able to write something like
template<ENUM T>someMethod(Data<T, SomeClass> data) {
for_single_or_pair {
/*
* Use data as if it would be of type SomeClass
*/
}
}
which should do the same as the combination of the following methods:
template<>someMethod(Data<ENUM::SINGLE, SomeClass> data) {
data.doStuff();
}
template<>incrementData(Data<ENUM::PAIR, SomeClass> data) {
data.first.doStuff();
data.second.doStuff();
}
I.e. I want to be able to use a pair of objects (of the same type) as if it would be a single object. Of course I could reimplement the methods of a type T for Data<ENUM::PAIR, T> (see the answer of dau_sama) which for the given example would look like:
template<>Data<ENUM::PAIR, SomeClass> : public std::pair<SomeClass, SomeClass> {
doStuff() {
this->first.doStuff();
this->second.doStuff();
}
};
But I would have to do this for many methods and operators and many different types, although the methods and operators would all look like this example.
The syntax of the solution may be very different from what I wrote above, this is just to demonstrate what I want to achieve. I would prefer a solution without macros, but could also live with that.
Can such an abstraction be realized in C++11?
The reasons I want to do this are
I do not have to specialize templated methods that shall work for ENUM::Single and ENUM::PAIR when all differences between the specializations would math the pattern above (avoid a lot of code duplication).
The same pattern is occuring very often in my code and I could avoid implementing workarounds in many places, which would be almost identical in each case.
You could try to create a template method applyMethod. Here is a complete example. I used an Executor class containing only one static method because I could not find a better way to process methods taking any types of parameters
#include <iostream>
#include <string>
enum ENUM {SINGLE, PAIR};
// General data type
template<ENUM T, class U>class Data {
};
// Partially specialized for single objects
template<class U>
class UData : public Data<ENUM::SINGLE, U>, public U {
// Forward Constructors, ...
public:
UData(const U& u): U(u) {};
};
// Partially specialized for pairs of objects
template<class U>
class PData : public Data<ENUM::PAIR, U>, public std::pair<U,U> {
// Forward Constructors, ...
public:
PData(const U& u1, const U& u2): std::pair<U, U>(u1, u2) {};
};
template <class U, typename... P>
class Executor {
Executor() = delete;
public:
template<void (U::*M)(P... params)>
static void applyMethod(Data<ENUM::SINGLE, U> &data, P ...params) {
UData<U>& ud= reinterpret_cast<UData<U>& >(data);
U& u = static_cast<U&>(ud);
(u.*M)(params...);
}
template<void (U::*M)(P... params)>
static void applyMethod(Data<ENUM::PAIR, U> &data, P ...params) {
PData<U>& pd = reinterpret_cast<PData<U>& >(data);
(pd.first.*M)(params...);
(pd.second.*M)(params...);
}
};
class X {
std::string name;
public:
X(const std::string& name): name(name) { };
void doStuff(void) {
std::cout << "DoStuff : " << name << std::endl;
}
void doStuff(int i) {
std::cout << "DoStuff : " << name << " - " << i << std::endl;
}
};
int main() {
X x1("x1");
X x2("x2");
X x3("x3");
UData<X> data1(x1);
PData<X> data2(x2, x3);
Executor<X>::applyMethod<&X::doStuff>(data1);
Executor<X, int>::applyMethod<&X::doStuff>(data2, 12);
return 0;
}
You could add a common method to your classes
template<class U>
Data<ENUM::SINGLE, U> : public U {
// Forward Constructors, ...
void handle() {
//do some specific handling for this type
return;
}
};
Now someMethod will just call the right "handle" and it'll automatically switch between the two
template<typename T>
someMethod(T& data) {
data.handle();
}
//If you want to bind your function to some other name, you could
//create a functor that calls someMethod with the arguments passed in _1
//I haven't tested it, there might be some syntax problems with the way you pass in the function name
auto someOtherMethod = std::bind (someMethod, _1);
If your type doesn't implement a handle method, you'll have a nasty compilation error. If you want to provide a default implementation and avoid a compilation error, there is a common pattern called SFINAE (Substitution failure is not an error) that does exactly that.
Here's an alternative to the solution to that from Serge Ballesta, using lambdas.
#include <functional>
template<ENUM T, class U>void for_single_or_pair(
Data<T, U>& data,
std::function<void(U&)> function);
template<class U>void for_single_or_pair(
Data<ENUM::SINGLE, U>& data,
std::function<void(U&)> function) {
function(data);
}
template<class U>void for_single_or_pair(
Data<ENUM::PAIR, U>& data,
std::function<void(U&)> function) {
function(data.first);
function(data.second);
}
Usage:
template<ENUM T>someMethod(Data<T, SomeClass> data) {
for_single_or_pair(data,[](SomeClass& someObject) {
// Play around with someObject in any way
});
}
In this way additionally to use member methods of SomeClass, the data can be used in any other way.
I would be happy about comments to this solution (and if it could be generalized to use more than one Data inside the for_single_or_pair method).
Related
I have a class and need to validate that it's function calls are being called w/ the right parameters. The function signature is always the same (sans 1 argument type). So, naturally I went for a templated approach. So generally the validation policy would have a template parameter per data type it could handle:
using P = Policy<int, double, UserDefined>
Or something of that ilk.
I got it to compile, but the caveat is that if double and int (or anything a double can convert to actually) are both template parameters, the double will be implicitly converted.
The policy looks like this:
template <typename... T>
class BasicValidationPolicy { };
template <>
class BasicValidationPolicy<>
{
public:
void RegisterSetHandler();
};
template <typename T, typename... Rest>
class BasicValidationPolicy<T, Rest...> : public BasicValidationPolicy<Rest...>
{
public:
using SetHandler = std::function<void(int, T)>;
void RegisterSetHandler(const SetHandler& handler)
{
m_setHandler = handler;
}
void Set(int n, const T& val) {
if (m_setHandler) {
m_setHandler(n, val);
}
}
private:
SetHandler m_setHandler{nullptr};
};
The class that uses it...
template <typename ValidatorPolicy>
class MyClass : public ValidatorPolicy {
public:
void OnSetInt(int n, int64_t v)
{
ValidatorPolicy::Set(n, v);
}
void OnSetDouble(int n, double d)
{
ValidatorPolicy::Set(n, d);
}
};
Usage:
int main()
{
using Policy = BasicValidationPolicy<int64_t, double>; // doesn't work
MyClass<Policy> m;
m.Policy::RegisterSetHandler([](int i, double value) {
// by this point value is an int64_t
std::cout << "Got double " << i << ", " << value << "\n";
});
double d{35.2135};
m.OnSetDouble(1, d);
}
To boot, doing this does work
using Policy = BasicValidationPolicy<double, int64_t>;
So I guess I'm missing something about the template deduction. Looks like it tries to match double against std::int64_t says "meh, good enough", and moves on. Nice to know a way around it (kind of) but that looks like it would be very tricky to maintain.
It's complicated...
First of all: you have a recursive template class, BasicValidationPolicy, where you define two methods and you want that all methods, for all recursion steps of the class, are available.
Unfortunately, the definition of the methods in the derived classes hide the method in base classes.
To un-hide the inherited methods, you have to explicitly add a pair of using
using BasicValidationPolicy<Rest...>::Set;
using BasicValidationPolicy<Rest...>::RegisterSetHandler;
At this point, the code doesn't compile because you need a Set() and a RegisterSetHandler() in the ground case class. You have declared a dummy RegisterSetHandler() but not a dummy Set(). You have to add one, so the ground case become
template <>
class BasicValidationPolicy<>
{
public:
void RegisterSetHandler();
void Set();
};
Now your MyClass<Policy> object expose two RegisterSetHandler() methods (before only one): one receiving a std::function<void(int, std::int64_t)>, the other (before hidden) receiving a std::function<void(int, double)>.
But when you pass a lambda, you have a chicken-and-egg problem: the lambda can be converted to a std::function but isn't a std::function. So can't be used to deduce the template parameters of std::function because the types are to be known before to deduce them.
A possible solution is impose a lambda/std::function conversion in the call
// ..........................VVVVVVVVVVVVVV
m.Policy::RegisterSetHandler(std::function{[](int i, double value) {
// by this point value is an int64_t
std::cout << "Got double " << i << ", " << value << "\n";
}});
// ...........................^
using also the template deduction guides introduced in C++17.
So your code become
#include <iostream>
#include <functional>
template <typename... T>
class BasicValidationPolicy { };
template <>
class BasicValidationPolicy<>
{
public:
void RegisterSetHandler();
void Set();
};
template <typename T, typename... Rest>
class BasicValidationPolicy<T, Rest...> : public BasicValidationPolicy<Rest...>
{
public:
using SetHandler = std::function<void(int, T)>;
using BasicValidationPolicy<Rest...>::Set;
using BasicValidationPolicy<Rest...>::RegisterSetHandler;
void RegisterSetHandler(const SetHandler& handler)
{
m_setHandler = handler;
}
void Set(int n, const T& val) {
if (m_setHandler) {
m_setHandler(n, val);
}
}
private:
SetHandler m_setHandler{nullptr};
};
template <typename ValidatorPolicy>
class MyClass : public ValidatorPolicy {
public:
void OnSetInt(int n, int64_t v)
{
ValidatorPolicy::Set(n, v);
}
void OnSetDouble(int n, double d)
{
ValidatorPolicy::Set(n, d);
}
};
int main ()
{
using Policy = BasicValidationPolicy<int64_t, double>; // doesn't work
MyClass<Policy> m;
m.Policy::RegisterSetHandler(std::function{[](int i, double value) {
std::cout << "Got double " << i << ", " << value << "\n";
}});
double d{35.2135};
m.OnSetDouble(1, d);
}
There's a small alternative to the recursive definition that might be easier to work with...
template<typename T>
class ValidationPolicy {
// Set/Register/etc
};
template <typename... Ts>
class BasicValidationPolicy : public ValidationPolicy<Ts>... {
public:
using ValidationPolicy<Ts>::Set...;
using ValidationPolicy<Ts>::RegisterSetHandler...;
};
This can have some impacts on compile time and other aspects of development, though most likely relatively minor. For instance, if you have dozens of classes used in hundreds of different policy combinations in your app, the recursive definition will lead to many more distinct types and larger binaries to support that. For example, in the recursive definition BasicValidationPolicy<T1, T2, T3> and BasicValidationPolicy<T3, T2, T1> being used would generate 7 distinct types in a hierarchy (the empty one is shared in both expansions). The same thing in the flatter hierarchy would be 5 distinct types - one for each of T1, T2, T3 and one for each combination. Adding in BasicValidationPolicy<T2, T3, T1> would add 3 more types recursively but 1 more type in the flat form.
The answer from #max66 isn't wrong, just something else to think about.
I have two different classes
class A_class {
public:
string member_to_add_to;
}
and
class B_class {
string member_to_add_to;
}
They both are almost similar with a slight difference in member variables. There is no inheritance involved. They both are used in different sections that do not merge together. I know it is not a good design but we don't have time to fix it now as the code base is large.
Then there is the Modifier class that takes a reference to an object of either A_class or B_class and makes some modifications to the class objects.
class Modifier() {
method1(A_class& object_ or B_class& object);
method2(A_class& object_ or B_class& object);
}
I need to write a function called doSomething() inside the Modifier class that takes in an object that is either A_class or B_class along with a string parameter that sets a member variable member_to_add_to to the string parameter and calls other methods within Modifier. Exactly only two lines differ based on they type of object being fed into this function.
void doSomething(A_class (or) B_class object_to_modify, string member_value) {
object_to_modify.member_to_add_to = member_value;
// after this 5 to 10 steps that call other methods taking a reference to object_to_modify but do the same thing
method1(object_to_modify);
method2(object_to_modify);
//etc.,
}
Apart from the fact that it involves these two classes, everything else inside this function is the same exact code.
Should I just use function overloading for both the objects separately and replicate the code inside it twice in 2 functions except for the lines that differ?
Is there a more optimized/readable way of doing this?
Use a template function:
#include <iostream>
#include <type_traits>
struct A {
char const* data;
};
struct B {
char const* data;
};
template <typename T,
std::enable_if_t<std::is_same_v<T, A> || std::is_same_v<T, B>, int> = 0
>
void doSomething(T const& arg) {
std::cout << arg.data << '\n';
}
int main() {
A a{"Hello "};
B b{"World"};
foo(a);
foo(b);
// foo("something else"); // Doesn't compile
}
Slightly less cluttered with C++20 concepts:
#include <concepts>
template <typename T>
void doSomething(T const& arg) requires (std::same_as<T, A> || std::same_as<T, B>) {
std::cout << arg.data << '\n';
}
You could even over-engineer such a concept into your code-base if this is a common issue you have:
template <typename T, typename ...Types>
concept one_of = (std::same_as<T, Types> || ...);
template <one_of<A, B> T>
void doSomething(T const& arg) {
std::cout << arg.data << '\n';
}
You might use template:
template <typename AorB>
void doSomething(AorB& object_to_modify, string member_value) {
object_to_modify.member_to_add_to = member_value;
// after this 5 to 10 steps that call other methods taking a reference to object_to_modify but do the same thing
method1(object_to_modify);
method2(object_to_modify);
//etc.,
}
I would like to implement a generic factory mechanism for a set of derived classes that allows me to generically implement not only a factory function to create objects of that class, but also creators of other template classes which take as template arguments one of the derived classes.
Ideally a solution would only use C++17 features (no dependencies).
Consider this example
#include <iostream>
#include <string>
#include <memory>
struct Foo {
virtual ~Foo() = default;
virtual void hello() = 0;
};
struct FooA: Foo {
static constexpr char const* name = "A";
void hello() override { std::cout << "Hello " << name << std::endl; }
};
struct FooB: Foo {
static constexpr char const* name = "B";
void hello() override { std::cout << "Hello " << name << std::endl; }
};
struct FooC: Foo {
static constexpr char const* name = "C";
void hello() override { std::cout << "Hello " << name << std::endl; }
};
struct BarInterface {
virtual ~BarInterface() = default;
virtual void world() = 0;
};
template <class T>
struct Bar: BarInterface {
void world() { std::cout << "World " << T::name << std::endl; }
};
std::unique_ptr<Foo> foo_factory(const std::string& name) {
if (name == FooA::name) {
return std::make_unique<FooA>();
} else if (name == FooB::name) {
return std::make_unique<FooB>();
} else if (name == FooC::name) {
return std::make_unique<FooC>();
} else {
return {};
}
}
std::unique_ptr<BarInterface> bar_factory(const std::string& foo_name) {
if (foo_name == FooA::name) {
return std::make_unique<Bar<FooA>>();
} else if (foo_name == FooB::name) {
return std::make_unique<Bar<FooB>>();
} else if (foo_name == FooC::name) {
return std::make_unique<Bar<FooC>>();
} else {
return {};
}
}
int main()
{
auto foo = foo_factory("A");
foo->hello();
auto bar = bar_factory("C");
bar->world();
}
run it
I am looking for a mechanism that would allow me to implement both foo_factory and bar_factory without listing all classes, such that they do not need to be updated once I add for example FooD as an additional derived class. Ideally, the different Foo derivatives would somehow "self-register", but listing them all in one central place is also acceptable.
Edit:
Some clarifications based on comments / answers:
It is necessary in my case to invoke the factories with (something like) a string, since the callers of the factories use polymorphism with Foo / BarInterface, i.e. they don't know about the concrete derived classes. On the other hand in Bar we want to use template methods of the derived Foo classes and facilitate inlining, that's why we really need the templated derived Bar classes (rather than accessing Foo objects through some base-class interface).
We can assume that all derived Foo classes are defined in one place (and a manual registration where we list them all once in the same place is therefore acceptable, if necessary). However, they do not know about the existence of Bar, and in fact we have multiple different classes like BarInterface and Bar. So we cannot create "constructor objects" of Bar and save them in a map the same way we can do it for a foo_factory. What I think is needed is some kind of "compile-time map" (or list) of all the derived Foo types, such that when defining the bar_factory, the compiler can iterate over them, but I don't know how to do that...
Edit2:
Additional constraints that proofed to be relevant during discussion:
Templates and template templates: The Foo are actually templates (with a single class argument) and the Bar are template templates taking a concrete Foo as template argument. The Foo templates have no specializations and all have the same "name", so querying any concrete type is fine. In particular SpecificFoo<double>::name is always valid. #Julius' answer has been extended to facilitate this already. For #Yakk's the same can probably be done (but it will take me some time for figure it out in detail).
Flexible bar factory code: The factory for Bar does a little more than just call the constructor. It also passes some arguments and does some type casting (in particular, it may have Foo references that should be dynamic_cast to the corresponding concrete derived Foo). Therefore a solution that allows to write this code inline during definition of the bar_factory seems most readable to me. #Julius' answer works great here, even if the loop code with tuples is a little verbose.
Making the "single place" listing the Foos even simpler: From the answers so far I believe the way to go for me is having a compile-time list of foo types and a way to iterate over them. There are two answers that define a list of Foo types (or templates) in one central place (either with a types template or with tuples), which is already great. However, for other reasons I already have in the same central place a list of macro calls, one for each foo, like DECLARE_FOO(FooA, "A") DECLARE_FOO(FooB, "B") .... Can the declaration of FooTypes be somehow take advantage of that, so I don't have to list them again? I guess such type lists cannot be declared iteratively (appending to an already existing list), or can it? In the absence of that, probably with some macro magic it would be possible. Maybe always redefining and thus appending to a preprocessor list in the DECLARE_FOO calls, and then finally some "iterate over loop" to define the FooTypes type list. IIRC boost preprocessor has facilities to loop over lists (although I don't want a boost dependency).
For some more context, you can think of the different Foo and it's template argument as classes similar to Eigen::Matrix<Scalar> and the Bar are cost functors to be used with Ceres. The bar factory returns objects like ceres::AutoDiffCostFunction<CostFunctor<SpecificFoo>, ...> as ceres::CostFunction* pointers.
Edit3:
Based on #Julius' answer I created a solution that works with Bars that are templates as well as template templates. I suspect one could unify bar_tmpl_factory and bar_ttmpl_factory into one function using variadic variadic template templates (is that a thing?).
run it
TODO:
combine bar_tmpl_factory and bar_ttmpl_factory
the point Making the "single place" listing the Foos even simpler from above
maybe replacing the use of tuples with #Yakk's types template (but in a way such that the creator function can be defined inline at the call site of the loop over all foo types).
I consider the question answered and if anything the above points should be separate questions.
template<class...Ts>struct types_t {};
template<class...Ts>constexpr types_t<Ts...> types{};
that lets us work with bundles of types without the overhead of a tuple.
template<class T>
struct tag_t { using type=T;
template<class...Ts>
constexpr decltype(auto) operator()(Ts&&...ts)const {
return T{}(std::forward<Ts>(ts)...);
}
};
template<class T>
constexpr tag_t<T> tag{};
this lets us work with types as values.
Now a type tag map is a function that takes a type tag, and returns another type tag.
template<template<class...>class Z>
struct template_tag_map {
template<class In>
constexpr decltype(auto) operator()(In in_tag)const{
return tag< Z< typename decltype(in_tag)::type > >;
}
};
this takes a template type map and makes it into a tag map.
template<class R=void, class Test, class Op, class T0 >
R type_switch( Test&&, Op&& op, T0&&t0 ) {
return static_cast<R>(op(std::forward<T0>(t0)));
}
template<class R=void, class Test, class Op, class T0, class...Ts >
auto type_switch( Test&& test, Op&& op, T0&& t0, Ts&&...ts )
{
if (test(t0)) return static_cast<R>(op(std::forward<T0>(t0)));
return type_switch<R>( test, op, std::forward<Ts>(ts)... );
}
that lets us test a condition on a bunch of types, and run an operation on the one that "succeeds".
template<class R, class maker_map, class types>
struct named_factory_t;
template<class R, class maker_map, class...Ts>
struct named_factory_t<R, maker_map, types_t<Ts...>>
{
template<class... Args>
auto operator()( std::string_view sv, Args&&... args ) const {
return type_switch<R>(
[&sv](auto tag) { return decltype(tag)::type::name == sv; },
[&](auto tag) { return maker_map{}(tag)(std::forward<Args>(args)...); },
tag<Ts>...
);
}
};
now we want to make shared pointers of some template class.
struct shared_ptr_maker {
template<class Tag>
constexpr auto operator()(Tag ttag) {
using T=typename decltype(ttag)::type;
return [](auto&&...args){ return std::make_shared<T>(decltype(args)(args)...); };
}
};
so that makes shared pointers given a type.
template<class Second, class First>
struct compose {
template<class...Args>
constexpr decltype(auto) operator()(Args&&...args) const {
return Second{}(First{}( std::forward<Args>(args)... ));
}
};
now we can compose function objects at compile time.
Next wire it up.
using Foos = types_t<FooA, FooB, FooC>;
constexpr named_factory_t<std::shared_ptr<Foo>, shared_ptr_maker, Foos> make_foos;
constexpr named_factory_t<std::shared_ptr<BarInterface>, compose< shared_ptr_maker, template_tag_map<Bar> >, Foos> make_bars;
and Done.
The original design was actually c++20 with lambdas instead of those structs for shared_ptr_maker and the like.
Both make_foos and make_bars have zero runtime state.
What I think is needed is some kind of "compile-time map" (or list) of
all the derived Foo types, such that when defining the bar_factory,
the compiler can iterate over them, but I don't know how to do that...
Here is one basic option:
#include <cassert>
#include <tuple>
#include <utility>
#include "foo_and_bar_without_factories.hpp"
////////////////////////////////////////////////////////////////////////////////
template<std::size_t... indices, class LoopBody>
void loop_impl(std::index_sequence<indices...>, LoopBody&& loop_body) {
(loop_body(std::integral_constant<std::size_t, indices>{}), ...);
}
template<std::size_t N, class LoopBody>
void loop(LoopBody&& loop_body) {
loop_impl(std::make_index_sequence<N>{}, std::forward<LoopBody>(loop_body));
}
////////////////////////////////////////////////////////////////////////////////
using FooTypes = std::tuple<FooA, FooB, FooC>;// single registration
std::unique_ptr<Foo> foo_factory(const std::string& name) {
std::unique_ptr<Foo> ret{};
constexpr std::size_t foo_count = std::tuple_size<FooTypes>{};
loop<foo_count>([&] (auto i) {// `i` is an std::integral_constant
using SpecificFoo = std::tuple_element_t<i, FooTypes>;
if(name == SpecificFoo::name) {
assert(!ret && "TODO: check for unique names at compile time?");
ret = std::make_unique<SpecificFoo>();
}
});
return ret;
}
std::unique_ptr<BarInterface> bar_factory(const std::string& name) {
std::unique_ptr<BarInterface> ret{};
constexpr std::size_t foo_count = std::tuple_size<FooTypes>{};
loop<foo_count>([&] (auto i) {// `i` is an std::integral_constant
using SpecificFoo = std::tuple_element_t<i, FooTypes>;
if(name == SpecificFoo::name) {
assert(!ret && "TODO: check for unique names at compile time?");
ret = std::make_unique< Bar<SpecificFoo> >();
}
});
return ret;
}
Write a generic factory like the following that allows registration at the class site:
template <typename Base>
class Factory {
public:
template <typename T>
static bool Register(const char * name) {
get_mapping()[name] = [] { return std::make_unique<T>(); };
return true;
}
static std::unique_ptr<Base> factory(const std::string & name) {
auto it = get_mapping().find(name);
if (it == get_mapping().end())
return {};
else
return it->second();
}
private:
static std::map<std::string, std::function<std::unique_ptr<Base>()>> & get_mapping() {
static std::map<std::string, std::function<std::unique_ptr<Base>()>> mapping;
return mapping;
}
};
And then use it like:
struct FooA: Foo {
static constexpr char const* name = "A";
inline static const bool is_registered = Factory<Foo>::Register<FooA>(name);
inline static const bool is_registered_bar = Factory<BarInterface>::Register<Bar<FooA>>(name);
void hello() override { std::cout << "Hello " << name << std::endl; }
};
and
std::unique_ptr<Foo> foo_factory(const std::string& name) {
return Factory<Foo>::factory(name);
}
Note: there is no way to guarantee that the class would be registered. The compiler might decide not to include the translation unit, if there are no other dependencies. It is probably better to simply register all classes in one central place. Also note that the self-registering implementation depends on inline variables (C++17). It is not a strong dependence, and it is possible to get rid of it by declaring the booleans in the header and defining them in the CPP (which makes self-registering uglier and more prone to failing to register).
edit
The disadvantage of this answer, when compared to others, is that it performs the registration during start-up and not during compilation. On the other hand, this makes the code much simpler.
The examples above assume that the definition of Bar<T> is moved above Foo. If that is impossible, then the registration can be done in an initialization function, in a cpp:
// If possible, put at the header file and uncomment:
// inline
const bool barInterfaceInitialized = [] {
Factory<Foo>::Register<FooA>(FooA::name);
Factory<Foo>::Register<FooB>(FooB::name);
Factory<Foo>::Register<FooC>(FooC::name);
Factory<BarInterface>::Register<Bar<FooA>>(FooA::name);
Factory<BarInterface>::Register<Bar<FooB>>(FooB::name);
Factory<BarInterface>::Register<Bar<FooC>>(FooC::name);
return true;
}();
In C++17, we can apply the fold expression to simplify the storing process of generating functions std::make_unique<FooA>(), std::make_unique<FooB>(), and so on into the factory class in this case.
To begin with, for convenience, let us define the following type alias Generator which describes the type of each generating function [](){ return std::make_unique<T>(); }:
template<typename T>
using Generator = std::function<std::unique_ptr<T>(void)>;
Next, we define the following rather generic functor createFactory which returns each factory as a hash map std::unordered_map.
Here I apply the fold expression with the comma operators.
For instance, createFactory<BarInterface, Bar, std::tuple<FooA, FooB, FooC>>()() returns the hash map corresponding to your function bar_factory:
template<typename BaseI, template<typename> typename I, typename T>
void inserter(std::unordered_map<std::string_view, Generator<BaseI>>& map)
{
map.emplace(T::name, [](){ return std::make_unique<I<T>>(); });
}
template<typename BaseI, template<typename> class I, typename T>
struct createFactory {};
template<typename BaseI, template<typename> class I, typename... Ts>
struct createFactory<BaseI, I, std::tuple<Ts...>>
{
auto operator()()
{
std::unordered_map<std::string_view, Generator<BaseI>> map;
(inserter<BaseI, I, Ts>(map), ...);
return map;
}
};
This functor enables us to list FooA, FooB, FooC, ... all in one central place as follows:
DEMO (I also added virtual destructors in base classes)
template<typename T>
using NonInterface = T;
// This can be written in one central place.
using FooTypes = std::tuple<FooA, FooB, FooC>;
int main()
{
const auto foo_factory = createFactory<Foo, NonInterface, FooTypes>()();
const auto foo = foo_factory.find("A");
if(foo != foo_factory.cend()){
foo->second()->hello();
}
const auto bar_factory = createFactory<BarInterface, Bar, FooTypes>()();
const auto bar = bar_factory.find("C");
if(bar != bar_factory.cend()){
bar->second()->world();
}
return 0;
}
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());
}
I am having trouble going the second step or level in templating my code. I have stripped the code to its bare essentials for readability.
I have looked through a lot of templates questions, but I was not really able to solve my exact issue.
I currently have a class RIVRecord, which I templated like this
template <class T>
class RIVRecord
{
private:
std::vector<T> values;
public:
std::string name;
RIVRecord(std::string _name, std::vector<T> _values) { name = _name; values = _values; };
~RIVRecord(void) { };
size_t size() {
return values.size();
}
T* Value(int index) {
return &values[index];
}
}
Easy enough. The T types are usually primitive types such as floats and integers. Then I want to put these RIVRecords in a DataSet class. Here is where I am having more difficulty. Untemplated it would be something like this:
class RIVDataSet
{
private :
//How to template this??
vector<RIVRecord<float>> float_records;
vector<RIVRecord<int>> int_records;
public:
RIVDataSet(void);
~RIVDataSet(void);
//And this
void AddRecord(RIVRecord<float> record) {
//How would this work?
}
//And this?
RIVRecord<float> GetFloatRecord();
};
I come from a Java background, so there I could use the vector<?> and do type checking whenever I ask a RIVRecord. But this does not seem possible in C++. I tried using variadic templates but am unsure how to construct the vector using all types in the template :
template <class... Ts>
class RIVDataSet
{
private :
//For each T in Ts
vector<RIVRecord<T>> records;
public:
RIVDataSet(void);
~RIVDataSet(void);
//For each T in Ts
void AddRecord(RIVRecord<T> record) {
//How would this work?
}
//For each T in Ts, get the record by index.
RIVRecord<T> GetRecord(int index);
};
I already saw that this sort of iteration in C++ templates is not possible, but it is just to clarify what I would want.
Any help is very welcome, thank you.
EDIT:
There is no restriction on the number of types (floats, ints,...) for T
Also, GetRecord works by having an index, but I don't really care about it that much, as long as I can iterate over the records and get the right type.
Solving this via variadic templates is not very complicated, but requires some additional support types. Let us begin, by looking at the result:
template <typename... V>
class many_vectors
{
static_assert(are_all_different<V...>::value, "All types must be different!");
std::tuple<std::vector<V>...> _data;
public:
template<typename T>
std::vector<T>& data()
{ return std::get<index_of<T, V...>::value>(_data); }
template<typename T>
std::vector<T> const& data() const
{ return std::get<index_of<T, V...>::value>(_data); }
template<typename T>
void push_back(T&& arg)
{ data<typename std::remove_reference<T>::type>().push_back(std::forward<T>(arg)); }
template<typename T, typename... W>
void emplace_back(W&&... args)
{ data<T>().emplace_back(std::forward<W>(args)...); }
};
The static_assert defines a very important requirement: Since we are differentiating on types, we must ensure that all types are different. The _data member is a std::tuple of the vectors for the different types, and corresponds directly to your float_records and int_records members.
As an example of providing a member function that refers to one of the vectors by their type the data function exposes the individual vectors. It uses a helper template to figure out which element of the tuple corresponds to your type and gets the result.
The push_back function of the vectors is also exposed to show how to use that to provide functions on these. Here std::forward is used to implement perfect forwarding on the argument to provide optimal performance. However, using rvalue references in combination with templates parameter deduction can lead to slightly unexpected results. Therefore, any reference on the T parameter is removed, so this push_back will not work for a many_vectors containing reference types. This could be fixed by instead providing two overloads push_back<T>(T&) and push_back<T>(T const&).
Finally, the emplace_back exposes a function that cannot rely on template parameter argument deduction to figure out which vector it is supposed to utilize. By keeping the T template parameter first, we allow a usage scenario in which only T is explicitly specified.
Using this, you should be ably to implement arbitrary additional members with similar funcitonality (e.g. begin<T> and end<T>).
Helpers
The most important helper is very simple:
template<typename T, typename U, typename... V>
struct index_of : std::integral_constant<size_t, 1 + index_of<T, V...>::value>
{ };
template<typename T, typename... V>
struct index_of<T, T, V...> : std::integral_constant<size_t, 0>
{ };
This will fail with a fairly ugly error message, if the first argument is not one of the following at all, so you may wish to improve on that.
The other helper is not much more complicated:
template<typename T, typename... V>
struct is_different_than_all : std::integral_constant<bool, true>
{ };
template<typename T, typename U, typename... V>
struct is_different_than_all<T, U, V...>
: std::integral_constant<bool, !std::is_same<T, U>::value && is_different_than_all<T, V...>::value>
{ };
template<typename... V>
struct are_all_different : std::integral_constant<bool, true>
{ };
template<typename T, typename... V>
struct are_all_different<T, V...>
: std::integral_constant<bool, is_different_than_all<T, V...>::value && are_all_different<V...>::value>
{ };
Usage
Yes, usage is as simple as you might hope:
v.push_back(int(3));
v.push_back<float>(4);
v.push_back<float>(5);
v.push_back(std::make_pair('a', 'b'));
v.emplace_back<std::pair<char, char>>('c', 'd');
std::cout << "ints:\n";
for(auto i : v.data<int>()) std::cout << i << "\n";
std::cout << "\n" "floats:\n";
for(auto i : v.data<float>()) std::cout << i << "\n";
std::cout << "\n" "char pairs:\n";
for(auto i : v.data<std::pair<char, char>>()) std::cout << i.first << i.second << "\n";
With the expected result:
ints:
3
floats:
4
5
char pairs:
ab
cd
You can use a technique called type erasure, you'll have to include another level of indirection however. Some general feedback:
RIVRecord(std::string _name, std::vector<T> _values)
Is better as:
RIVRecord(const std::string& _name, const std::vector<T>& _values)
In order to avoid unnecessary copies, overall the rule of thumb is to accept arguments as const& for most things which aren't a primitive.
T* Value(int index) { return &values[index]; }
Is dangerous, if the size() goes beyond capacity() of your vector< T > it will reallocate and invalidate all your pointers. A better interface in my opinion would be to have a T GetValue< T >() & void SetValue< T >( T a_Value ).
On to type erasure, this is how RIVDataSet could look, I'm using a library called Loki here, if you don't want to use Loki I'll give you some pointers afterwards.
class RIVDataSet
{
private :
//How to template this??
struct HolderBase
{
virtual ~HolderBase() {}
};
template< typename T >
struct HolderImpl : HolderBase
{
// Use pointer to guarantee validity of returned record
std::vector< RIVRecord< T >* > m_Record;
};
typedef Loki::AssocVector< Loki::TypeInfo, HolderBase* > HolderMap;
HolderMap m_Records;
public:
~RIVDataSet()
{
for( HolderMap::iterator itrCur = m_Records.begin(); itrCur != m_Records.end(); ++itrCur ) delete itrCur->second;
}
//And this
template< typename T >
void AddRecord(const RIVRecord< T >& record )
{
HolderMap::iterator itrFnd = m_Records.find( typeid( T ) );
if( itrFnd == m_Records.end() )
itrFnd = m_Records.insert( std::make_pair( Loki::TypeInfo( typeid( T ) ), new HolderImpl< T >() ) ).first;
static_cast< HolderImpl< T >* >( itrFnd->second )->m_Record.push_back( new RIVRecord< T >( record ) );
}
template< typename T >
RIVRecord< T >* GetRecord()
{
HolderMap::iterator itrFnd = m_Records.find( typeid( T ) );
assert( itrFnd != m_Records.end() );
return itrFnd == m_Records.end() ? 0 : static_cast< HolderImpl< T >* >( itrFnd->second )->m_Record.front();
}
};
Loki::AssocVector can be substituted for std::map, you do however need Loki::TypeInfo, which is just a wrapper for std::type_info. It's fairly easy to implement one your self if you take a look at the code for it in Loki.
One horrible idea if you really must do it as general is using the "type erasure idiom". It goes something like this (haven't compiled that though but I think it will, and can be further improved by type traits that would link RIVRecordsIndex::Float to the type float and prevent error)
class BaseRIVRecord
{
};
template <class T>
class RIVRecord : public BaseRIVRecord
{
};
enum class RIVRecordsIndex
{
Float, Int
};
class RIVDataSet
{
public:
template<RIVRecordsIndex I, typename T>
void addRecord()
{
allmightyRecords.resize(I+1);
allmightyRecords[I].push_back(new RIVRecord<T>());
}
template<RIVRecordsIndex I, typename T>
RIVRecord<T>* get(unsigned int index)
{
return static_cast<RIVRecord<T>*>(allmighyRecords[I][index]);
}
private:
std::vector<std::vector<BaseRIVRecord*>> allmightyRecords;
};
int main()
{
RIVDataSet set;
set.addRecord<RIVRecordsIndex::Float, float>();
set.addRecord<RIVRecordsIndex::Float, float>();
set.addRecord<RIVRecordsIndex::Int, int>();
RIVRecord<int> r = set.get<RIVRecordsIndex::Int, int>(0);
}
If you decide to do this stuff make sure you do not slice the inherited type (i.e. use vector of pointers). Do use some kind of type traits to prevent error calls like set.get. Again I have no time to actually compile that, it is just an idea thrown to further develop.
You can't use variadic templates to create multiple members of the same name but different type. In fact, you can never have two members with the same name. However, you can use multiple inheritance, and put the member in your base classes using variadic base classes. You can then use a member template in your derived class to resolve the ambiguity.
The example below also uses perfect forwarding to make sure that if a temporary is passed to add(), its resources can be "stolen". You can read more about that here.
Here is the example:
#include <vector>
#include <utility>
// This templated base class holds the records for each type.
template <typename T>
class Base {
public:
// "T &&v" is a universal reference for perfect forwarding.
void add(T &&v) { records.push_back(std::forward<T>(v)); }
private:
std::vector<T> records;
};
// This inherits from Base<int>, Base<double>, for example, if you instantiate
// DataSet<int, double>.
template <typename... Ts>
class DataSet : public Base<Ts>... {
public:
// The purpose of this member template is to resolve ambiguity by specifying
// which base class's add() function we want to call. "U &&u" is a
// universal reference for perfect forwarding.
template <typename U>
void add(U &&u) {
Base<U>::add(std::forward<U>(u));
}
};
int main() {
DataSet<int, double> ds;
ds.add(1);
ds.add(3.14);
}