Basically what I'm thinking about is:
template<typename... Types>
class Foo
{
void Bar(Types var) {};...
};
which when specialized like this:
Foo<S1, S2, S3> foo;
to expand to:
class Foo
{
void Bar(S1 var){};
void Bar(S2 var){};
void Bar(S3 var){};
};
Obviously, it does not make sense in some way but I'll be happy to see some thoughts.
template<class D, class T>
struct FooHelper {
void Bar(T var) {
auto* self=static_cast<D*>(this);
// here use self instead of this
};
};
template<typename... Types>
class Foo: FooHelper<Foo,Types>...
{
template<class D,class T>
friend struct FooHelper<D,T>;
};
this is how you do what you want to do.
We use use the CRTP to give the base class access to everything in Foo.
Here's a nice C++17 way to do that:
template<typename T>
struct HelpFoo {
void Bar(T) {}
};
template<typename... Types>
struct Foo : HelpFoo<Types>...
{
using HelpFoo<Types>::Bar...;
};
You can let your methods be templated, and use enable_if to enable those in the pack list:
#include <type_traits>
template<class... Ts>
struct foo {
template<class T, std::enable_if_t<
std::disjunction_v<std::is_same<T, Ts>...>, int> = 0>
void bar(T);
};
Related
Is there any way to check number of template parameters and compile time? I would like to do this (this is not real code):
template<typename... Types>
class Foo
{
// Enable this if count of 'Types' is 1.
Types[0] Bar()
{
return Types[0]{};
}
// Enable this otherwise.
std::variant<Types> Bar()
{
return std::variant<Types>{};
}
};
Is there any way to achieve this?
Not like that, at least not easily. You can probably add some helper struct that defines a type with if constexpr and sizeof...() and then use helper::return_type or seomthing.
But I think this calls for template specialization:
#include <variant>
template<typename... Types>
class Foo
{
std::variant<Types...> Bar()
{
return {};
}
};
// Specialize for just one Type
template<typename Type>
class Foo<Type>
{
Type Bar()
{
return {};
}
};
One option is to add a template parameter and then leverage constexpr if to check if the pack is empty or not like
template<typename first_t, typename... rest_t>
class Foo
{
auto Bar()
{
if constexpr (sizeof...(rest_t) == 0)
return first_t{};
else
return std::variant<first_t, rest_t...>{};
}
};
It's not too hard to create a alias template for the type by specializing a helper type:
template<class...Ts>
struct ReturnTypeHelper : std::type_identity<std::variant<Ts...>> {};
template<class T>
struct ReturnTypeHelper<T> : std::type_identity<T> {};
template<class...Ts>
using ReturnType = typename ReturnTypeHelper<Ts...>::type;
template<typename... Types>
class Foo
{
public:
auto Bar()
{
return ReturnType<Types...>{};
}
};
static_assert(std::is_same_v<decltype(std::declval<Foo<int>>().Bar()), int>);
static_assert(std::is_same_v<decltype(std::declval<Foo<int,float>>().Bar()), std::variant<int, float>>);
I will explain my question based on following example:
template <typename Param1, typename Param2>
class foo1
{
void lol();
};
template <typename Param1, typename Param2>
class foo2
{
void lol();
};
////////////////////////// FIRST OPTION //////////////////////////
template <typename Param1, typename Param2>
void func(foo1<Param1, Param2> a)
{
a.lol();
a.lol();
}
template <typename Param1, typename Param2>
void func(foo2<Param1, Param2> a)
{
a.lol();
}
////////////////////////// SECOND OPTION //////////////////////////
template <typename Foo_>
void func(Foo_ a)
{
a.lol();
a.lol();
}
///////////////////////////////////////////////////////////////////
int main()
{
return 0;
}
My goal is to write two overloads of func - for foo1 and foo2.
The FIRST OPTION works fine, but I don't like that I have to write template parameters for func that are not used in it.
Is there some way to avoid writing template parameters in signature of func?
I thought of writing something like this SECOND OPTION, but the problem is that overloads do different things.
The template parameters are used. Without them, foo1 and foo2 are just class templates and not a classes.
A simple way to minimize the typing would be to use template parameter packs:
template<class... T>
void func(foo1<T...> a) {
a.lol();
a.lol();
}
template<class... T>
void func(foo2<T...> a) {
a.lol();
}
If you need this check a lot, you can create concepts (since C++20):
#include <type_traits>
// concept for foo1:
template <class T> struct is_foo1 : std::false_type {};
template <class P1, class P2> struct is_foo1<foo1<P1, P2>> : std::true_type {};
template <typename T> concept Foo1Type = is_foo1<T>::value;
// concept for foo2:
template <class T> struct is_foo2 : std::false_type {};
template <class P1, class P2> struct is_foo2<foo2<P1, P2>> : std::true_type {};
template <typename T> concept Foo2Type = is_foo2<T>::value;
Then the func overloads become simpler:
void func(Foo1Type auto a) {
a.lol();
a.lol();
}
void func(Foo2Type auto a) {
a.lol();
}
Demo
I am trying to understand how to use std::enable_if to choose between 2 functions implementation. In this case, if the type TupleOfCallback doesn't contains all the type, it will not compile because std::get<...> will throw an error.
For exemple:
Executor<Entity1*, Entity2*> task([](Entity1 *e){}, [](Entity2 *2){});
This will not compile because Entity3* is not part of the tuple.
It seem that we can choose between two functions with the same prototype,
void Exec(Entity3 *entity)
{
//enabled when Entity3* is **not** in the tuple
}
OR
void Exec(Entity3 *entity)
{
//enabled when Entity3 is in the tuple
std::get<std::function<void(Entity3*)>>(m_Callbacks)(entity);
}
But i dont understand how to achieve this goal.
C++ template mechanism is still hard for me, any help is welcome.
template<typename ...T>
class Executor
{
typedef std::tuple<std::function<void(T)>...> TupleOfCallback;
public:
Executor(const std::function<void(T)> &...func)
{
}
void Exec(Entity1 *entity)
{
std::get<std::function<void(Entity1*)>>(m_Callbacks)(entity);
}
void Exec(Entity2 *entity)
{
std::get<std::function<void(Entity2*)>>(m_Callbacks)(entity);
}
void Exec(Entity3 *entity)
{
std::get<std::function<void(Entity3*)>>(m_Callbacks)(entity);
}
public:
TupleOfCallback m_Callbacks;
};
Building on this one Check if parameter pack contains a type. You can use two traits to select which method to call:
#include <iostream>
#include <type_traits>
struct Entity1 {};
struct Entity2 {};
struct Entity3 {};
template<typename What, typename ... Args>
struct is_present {
static constexpr bool value {(std::is_same_v<What, Args> || ...)};
};
template<typename T>
struct is_entity : is_present<T,Entity1,Entity2,Entity3> {};
template <typename T, typename ...Args>
struct is_present_entity {
static constexpr bool value = is_present<T,Args...>::value && is_entity<T>::value;
};
template <typename T, typename ...Args>
struct is_not_present_entity {
static constexpr bool value = (!is_present<T,Args...>::value) && is_entity<T>::value;
};
template<typename ...T>
class Executor
{
public:
template <typename U, std::enable_if_t< is_present_entity<U,T...>::value,bool> = true>
void Exec(U* t){
std::cout << "foo\n";
}
template <typename U, std::enable_if_t< is_not_present_entity<U,T...>::value,bool> = true>
void Exec(U* t){
std::cout << "bar\n";
}
};
struct foo {};
int main(void) {
Executor<Entity1,Entity2> ex;
Entity1 e1;
ex.Exec(&e1);
Entity3 e3;
ex.Exec(&e3);
// foo f;
// ex.Exec(&f);
}
output:
foo
bar
Another C++17 option:
template <typename T>
class ExecutorLeaf
{
public:
std::function<void(T)> callback;
void Exec(T entity) { callback(entity); }
};
template <typename... Ts>
class Executor : ExecutorLeaf<Ts>...
{
public:
Executor(const std::function<void(Ts)>&...funcs) : ExecutorLeaf<Ts>{funcs}... {}
using ExecutorLeaf<Ts>::Exec...; // C++17
// Fallback
template <typename T> void Exec(T) {}
};
Demo
If you can guarantee that all types appear only once, then the following should work:
template<typename... Ts>
class Executor {
using TupleOfCallback = std::tuple<std::function<void(Ts)>...>;
public:
Executor(const std::function<void(Ts)>&... func);
template<class E>
std::enable_if_t<(std::is_same_v<Ts, E*> || ...)>
Exec(E* entity) {
std::get<std::function<void(E*)>>(m_Callbacks)(entity);
}
template<class E>
std::enable_if_t<!(std::is_same_v<Ts, E*> || ...)>
Exec(E* entity)
{ }
public:
TupleOfCallback m_Callbacks;
};
The basic idea is to use fold-expression to detect whether E* is included in Ts..., thereby enabling the corresponding function.
Demo.
Suppose I have a class template Foo:
template<typename T, typename U>
struct Foo {
~Foo() = default;
// I want to reuse these methods for all instantiations of Foo
void bar() {}
void poi() {}
};
I want to specialize the destructor for any Foo<T, int>, but I want Foo<T, int> to share the other member functions with the general instantiations. But if I try to do:
template<typename T>
Foo<T, int>::~Foo()
{}
outside the class, it doesn't compile, the error being "invalid use of incomplete type struct Foo<T, int>". What does this error mean, and how can I achieve what I'm trying to do?
It is not possible to partially specialise a (non-templated) member function. You need to specialise the whole class.
One way to do what you want is to inherit the common functions.
template<typename T, typename U> struct MemberProvider
{
~MemberProvider() = default;
void bar() {};
void poi() {};
};
template<typename T, typename U>
struct Foo : public MemberProvider<T, U>
{
~Foo() = default;
// Optionally, you can still do this.
// However, note that these HIDE the inherited functions
void bar() {};
void poi() {};
};
template<typename T> struct Foo<T, int> : public MemberProvider<T, int>
{
~Foo() {};
};
Note you will also need to include any members acted on by the common functions in the inherited class.
However, I would suggest the above represents a code smell. If I saw code like the above in a production environment, I'd be contemplating the presence of a design flaw. Bear in mind that, when destructing such a class, the most derived destructor is invoked before base class destructors. MemberProvider is also not a polymorphic base.
You can explicitly specialize member functions of class templates, but you cannot partially specialize them - which is what you're trying to do.
If you need to partially specialize the destructor in a way that keeps the generic version defaulted, you'll have to partially specialize the whole class template:
template <class T, class U>
struct FooCommon {
~FooCommon() = default;
void bar() {}
void poi() {}
};
template <class T, class U>
struct Foo : FooCommon<T, U> { };
template <class T>
struct Foo<T, int> : FooCommon<T, int> {
~Foo() {
// special logic here
}
};
If foo and poi do things that depend on the template parameters, then you could extract your specialised destructor behaviour into a separate class, e.g.,
#include <iostream>
template <typename T, typename U>
struct Foo;
template <typename T, typename U>
struct FooDestructorTraits
{
static void destroy(Foo<T, U> * ptr)
{
std::cout << "default" << std::endl;
}
};
template <typename U>
struct FooDestructorTraits<int, U>
{
static void destroy(Foo<int, U> * ptr)
{
std::cout << "special" << std::endl;
}
};
template <typename T, typename U>
struct Foo
{
~Foo() noexcept { FooDestructorTraits<T, U>::destroy(this); }
void bar() {}
void baz() {}
};
int main() {
Foo<void, void> x;
Foo<int, void> y;
}
Suppose we have a class
template <int ... values>
struct foo;
now I have a function
template<typename foo_type, typename U>
void bar(foo_type a, U b);
where foo_type is basically foo. My issue is that, I do not want the variable a in the bar function. I want to be able to call the function like so
bar<foo<6,5,7,8,0>>(42);
but have all the parameters of foo available to me in bar. I tried changing the function to
template<template<int...> class foo_type, int ... args, typename U>
void bar(U b)
but this simply does not work. How can I do this? How can I change bar to the above way and still access the parameters in foo? Basically I want to do generic computation on those list at runtime
// within the body of bar
constexpr int[sizeof...(args)] = {args...};
where args is parameters of foo.
How opposed are you to having foo be an argument? Personally, I like having everything be an argument. Just wrap it in an empty type:
template <class T> struct tag_type { using type = T; };
template <class T> constexpr tag_type<T> tag{};
So that you can still template on the ints...:
template<int... Is, typename U>
void bar(tag_type<foo<Is...>> a, U b) {
constexpr int stuff[sizeof...(Is)] = {Is...};
// ...
}
Instead of calling bar<foo<6,5,7,8,0>>(42); you'd call bar(tag<foo<6,5,7,8,0>>, 42);, which is close enough.
To get exactly what you want, you can forward the former call to the latter:
namespace details {
template<int... Is, typename U>
void bar(tag_type<foo<Is...>> a, U b) {
constexpr int stuff[sizeof...(Is)] = {Is...};
// ...
}
}
template <typename foo_type, typename U>
void bar(U b) {
details::bar(tag<foo_type>, b);
}
And now it's the best of both worlds.
I believe, the question is about extracting template arguments from given foo type? If I am correct, here is the solution.
You will have to partially specialize a helper class, like following:
template <int ... values>
struct foo { };
template<class T>
struct bar_helper {};
template<int... values> struct bar_helper<foo<values...> > {
template<class T> static void bar(T ) {
// Use values... here
}
};
template<class foo_type, class U>
void bar(U b) {
bar_helper<foo_type>::bar(b);
}
void check() {
bar<foo<2, 3, 4, 5, 6> >(42);
}