I'm looking for a solution to a following problem:
#include <string>
class A
{
public:
template <typename T>
static typename std::enable_if<std::is_same<T, std::string>::value, void>::type foo(T val)
{
printf("std::string\n");
}
template<typename T, typename... Arg>
static void multiple(Arg&&... arg)
{
T::foo(arg...);
}
};
class B : public A
{
public:
template <typename T>
static typename std::enable_if<std::is_same<T, int>::value, void>::type foo(T val)
{
printf("int\n");
}
};
int main()
{
std::string a;
int b = 0;
A::multiple<B>(a, b);
}
All works fine if both foo methods are in the same class or I force foo from proper class (A::foo for std::string and B::foo for int), however I need more than one class, because base class must be extendable. I can't use simple specialization, because I need more SFINAE features like detect for std::pair, std::tuple etc. I also don't want to move foo methods from a class to a namespace. Do you have any Idea how can I solve this issue?
Here B::foo hides A::foo, you need a using:
class B : public A
{
public:
using A::foo;
template <typename T>
static typename std::enable_if<std::is_same<T, int>::value, void>::type foo(T val)
{
printf("int\n");
}
};
But
From namespace.udecl#15.sentence-1:
When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list, cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting)
Return type doesn't count, so you have to use std::enable_if in parameter:
class A
{
public:
template <typename T>
static void foo(T val, std::enable_if_t<std::is_same<T, std::string>::value, int> = 0)
{
printf("std::string\n");
}
};
class B : public A
{
public:
using A::foo;
template <typename T>
static void foo(T val, std::enable_if_t<std::is_same<T, int>::value, int> = 0)
{
printf("int\n");
}
};
Demo
Note: you also have typo for
template<typename T, typename... Arg>
static void multiple(Arg&&... arg)
{
T::foo(arg...); // B::foo(string, int)
}
which should be
template<typename T, typename... Arg>
static void multiple(Arg&&... arg)
{
(T::foo(arg), ...); // B::foo(string), B::foo(int)
}
Related
I am trying to create a class template that expects a type and a function pointer as template parameters. The function pointer is expected to be a member function of the type passed in. I want the user of the class template to be able to pass in a void member function of the type passed in. That member function will then be called on instances of the type passed in every time a certain function of the class template is called. It's a bit hard to explain but it's supposed to work sort of like this:
template<Type, Function> // For the purpose of explaining it
class Foo
{
public:
template<Args... args>
void callOnAll(Args... args)
{
for(Type* ptr : ptrs_)
{
ptr->Function(std::forward<Args>(args)...);
}
}
private:
std::vector<Type*> ptrs_;
}
Assuming that something like this is possible (which I realize it might not be), the key would have to be getting the template parameters for the class right, and getting the update function right. This is what I've come up with but I still can't get it to work:
template<typename T, template<typename... Args> void(T::*func)(Args... args)>
class EngineSystem
{
public:
template<typename... Args>
void update(Args... args)
{
for (T* handler : handlers_)
{
((*handler).*func)(std::forward<Args>(args)...);
}
}
private:
std::vector<T*> handlers_;
};
The code above does not compile. It points me to the line where I declare the template parameters for the class, underlines void and says expected 'class' or 'typename'.
Is it clear what I'm trying to achieve, and is it possible?
C++ doesn't allow non-type template template parameters. That means you can't have a parameter-pack for your member-function pointer parameter.
Assuming you're using C++17 or newer, you can use an auto template parameter instead:
template<typename T, auto func>
public:
template<typename... Args>
void update(Args... args)
{
for (T* handler : handlers_)
{
(handler->*func)(std::forward<Args>(args)...);
}
}
private:
std::vector<T*> handlers_;
};
Live Demo
Technically that will accept any object for func, but assuming update is called, then (handler->*func)(std::forward<Args>(args)...) still has to be well-formed or compilation will fail.
If you want compilation to fail even if update never gets called, you could use some type traits and a static_assert (or some SFINAE hackery, if you need it) to ensure that func is actually a pointer to a member function of T:
template <typename T, typename U>
struct IsPointerToMemberOf : std::false_type {};
template <typename T, typename U>
struct IsPointerToMemberOf<T, U T::*> : std::true_type {};
template <typename T, typename U>
struct IsPointerToMemberFunctionOf
: std::integral_constant<
bool,
IsPointerToMemberOf<T, U>::value && std::is_member_function_pointer<U>::value
>
{};
template<typename T, auto func>
class EngineSystem
{
static_assert(IsPointerToMemberFunctionOf<T, decltype(func)>::value, "func must be a pointer to a member function of T");
//...
};
Live Demo
#include <iostream>
#include <vector>
template <typename T, typename... Args>
class EngineSystem
{
public:
EngineSystem(void(T::*fun)(Args... args)): fun(fun)
{
}
void update(Args... args)
{
for (T* handler : handlers_)
{
(handler->*fun)(std::forward<Args>(args)...);
}
}
void push(T* t){
handlers_.push_back(t);
}
private:
void(T::*fun)(Args... args);
std::vector<T*> handlers_;
};
struct A {
int x = 3;
void fn(int a, int b){
std::cout << a << b << x;
}
};
template <typename T, typename... Args>
auto makeEngine(void(T::*fun)(Args... args)){
return EngineSystem<T, Args...>(fun);
}
int main() {
EngineSystem<A, int, int> as(&A::fn);
// or deduce types automatically
auto es = makeEngine(&A::fn);
A a;
es.push(&a);
es.update(1,2);
return 0;
}
https://gcc.godbolt.org/z/Pcdf9K9nz
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.
I have a templated class with a templated friend function declaration that is not having its signature matched when stated in a more direct, but seemingly equivalent, expression:
link to example on online compiler
#include <type_traits>
template <typename Sig> class Base;
template <typename R, typename ... Args> class Base<R(Args...)> { };
template <typename Sig, typename T> class Derived;
template <typename Sig> struct remove_membership;
template <typename T, typename R, typename ... Args>
class Derived<R(Args...), T> : public Base<R(Args...)> {
static void bar() { }
// XXX: why are these two not equivalent, and only the 1st version successful?
template <typename T2>
friend auto foo(T2 const &) -> Base<typename
remove_membership<decltype(&std::remove_reference_t<T2>::operator())>::type> *;
template <typename T2>
friend auto foo(T2 const &) -> Base<R(Args...)> *;
};
template <typename F, typename R, typename ... Args>
struct remove_membership<R (F::*)(Args...) const> {
using type = R(Args...);
};
template <typename T>
auto foo(T const &) -> Base<typename
remove_membership<decltype(&std::remove_reference_t<T>::operator())>::type> *
{
using base_param_t = typename remove_membership<
decltype(&std::remove_reference_t<T>::operator())>::type;
Derived<base_param_t, T>::bar();
return nullptr;
}
int main(int, char **) { foo([](){}); } // XXX blows up if verbose friend decl. removed.
Inside member definitions of Derived<R(Args...), T> (for example, in the body of bar()), the types match, adding to my confusion:
static_assert(std::is_same<Base<R(Args...)>, Base<typename
remove_membership<decltype(&std::remove_reference_t<T>::operator())>::type>>::value,
"signature mismatch");
Are there rules around template class template member function (and friend function) delarations and instantiations that make these preceding declarations distinct in some or all circumstances?
template <typename T2>
void foo(T2 const &)
template <typename T2>
auto foo(T2 const &)
-> std::enable_if_t<some_traits<T2>::value>;
Are 2 different overloads. Even if both return void (when valid).
2nd overload uses SFINAE.
(and yes, template functions can differ only by return type contrary to regular functions).
Your version is not identical but similar (&std::remove_reference_t<T>::operator() should be valid)
You can use the simpler template friend function:
template <typename T, typename R, typename ... Args>
class Derived<R(Args...), T> : public Base<R(Args...)> {
static void bar() { }
template <typename T2>
friend auto foo(T2 const &) -> Base<R(Args...)>*;
};
template <typename T>
auto foo(T const &) -> Base<void()>* // friend with Derived<void(), U>
{
using base_param_t = typename remove_membership<
decltype(&std::remove_reference_t<T>::operator())>::type;
Derived<base_param_t, T>::bar();
return nullptr;
}
Demo
but you have then to implement different version of the template foo.
The problem can be reduced to:
template<class T>
struct identity {
using type=T;
};
class X {
int bar();
public:
template<class T>
friend T foo();
};
template<class T>
typename identity<T>::type foo() { return X{}.bar(); }
int main() {
foo<int>(); // error: bar is a private member of X
}
Even though we know identity<T>::type is always T, the compiler doesn't know that and would be wrong to assume so. There could be a specialization of identity<T> somewhere later in the code that resolves to some type other than T.
Therefore when the compiler sees the second declaration of foo it won't assume that it is the same friend foo declared before.
In Java, it's possible to declare that a parameter implements multiple interfaces. You have to use generics syntax, but you can:
public <T extends Appendable & Closeable> void spew(T t) {
t.append("Bleah!\n");
if (timeToClose())
t.close();
}
In C++, a common pattern is to use classes containing only pure virtual functions as interfaces:
class IAppendable {
public:
virtual void append(const std::string&) = 0;
};
class ICloseable {
public:
virtual void close() = 0;
};
And it's trivial to write a function that takes an ICloseable (this is just polymorphism):
void closeThis(ICloseable&);
But what is the signature of a function that takes a parameter which, as in the Java example, inherits from both ICloseable and IAppendable?
Here is how you'd write it using only standard facilities :
template <class T>
std::enable_if_t<
std::is_base_of<IAppendable, T>{} && std::is_base_of<ICloseable, T>{},
void
> closeThis(T &t) {
t.append("end");
t.close();
}
Live on Coliru
If there were more base classes, I'd advise crafting a more concise type trait to check them all in the enable_if :
constexpr bool allTrue() {
return true;
}
template <class... Bools>
constexpr bool allTrue(bool b1, Bools... bools) {
return b1 && allTrue(bools...);
}
template <class T, class... Bases>
struct all_bases {
static constexpr bool value = allTrue(std::is_base_of<Bases, T>{}...);
constexpr operator bool () const {
return value;
}
};
template <class T>
std::enable_if_t<
all_bases<T, IAppendable, ICloseable>{},
void
> closeThis(T &t) {
t.append("end");
t.close();
}
#Quentin's excellent answer prompted me to write a generalized, variadicinherits template. It allows you to easily specify an arbitrary number of base classes.
#include <type_traits>
template<class... T> struct inherits :
std::true_type
{};
template<class T, class Base1, class... Bases>
struct inherits<T, Base1, Bases...> :
std::conditional_t< std::is_base_of<Base1, T>{},
inherits<T, Bases...>,
std::false_type
>
{};
The first template parameter is the type to check, and the remaining parameters are the types that the first type must inherit from.
For example,
class A {};
class B {};
class C {};
template<class T>
std::enable_if_t<
inherits<T, A, B, C>{},
void
> foo(const T& t)
{
// ...
}
Here, whatever type T is passed as an argument to foo must inherit from A, B, and C.
Live on Coliru
Consider the following function:
template<class F>
void register_handler( F& f ) // any callable object
{
// find out T - the argument type of f
}
Here f is some callable object, accepting one argument. It may be a function pointer, an std::function or a result of std::bind.
The problem is, how to determine the argument type of f and do some actions based on that type?
An easy workaround would be to add the type to template explicitly, like
template<class T, class F> // T is the argument type of F
void register_handler( F& f )
but this seems an overkill because type F should already contain the necessary information about type T.
Assuming F is any callable type, you cannot get its argument type. Consider this:
struct callable
{
void operator() (int);
void operator() (float *);
void operator() (std::string const &);
void operator() (std::list<int> &);
};
the type of argument is an ambiguity here.
This blogpost shows how to implement some function type traits. These should work with everything callable (exception: polymorphic functors :P). You could iterate over the arguments, and use their type to do some sfinae or as a additional template argument.
Function traits as copied from blogpost:
#include <tuple>
// as seen on http://functionalcpp.wordpress.com/2013/08/05/function-traits/
template<class F>
struct function_traits;
// function pointer
template<class R, class... Args>
struct function_traits<R(*)(Args...)> : public function_traits<R(Args...)>
{};
template<class R, class... Args>
struct function_traits<R(Args...)>
{
using return_type = R;
static constexpr std::size_t arity = sizeof...(Args);
template <std::size_t N>
struct argument
{
static_assert(N < arity, "error: invalid parameter index.");
using type = typename std::tuple_element<N,std::tuple<Args...>>::type;
};
};
// member function pointer
template<class C, class R, class... Args>
struct function_traits<R(C::*)(Args...)> : public function_traits<R(C&,Args...)>
{};
// const member function pointer
template<class C, class R, class... Args>
struct function_traits<R(C::*)(Args...) const> : public function_traits<R(C&,Args...)>
{};
// member object pointer
template<class C, class R>
struct function_traits<R(C::*)> : public function_traits<R(C&)>
{};
// functor
template<class F>
struct function_traits
{
private:
using call_type = function_traits<decltype(&F::operator())>;
public:
using return_type = typename call_type::return_type;
static constexpr std::size_t arity = call_type::arity - 1;
template <std::size_t N>
struct argument
{
static_assert(N < arity, "error: invalid parameter index.");
using type = typename call_type::template argument<N+1>::type;
};
};
template<class F>
struct function_traits<F&> : public function_traits<F>
{};
template<class F>
struct function_traits<F&&> : public function_traits<F>
{};
Testcode:
#include <iostream>
class A
{
};
template <class T>
struct Functor
{
void operator()(const T& t)
{}
};
struct Register
{
//int parameters
template <class T>
static void RegisterFunctor(const T& /*functor*/, typename std::enable_if<std::is_same<typename function_traits<T>::template argument<0>::type, const int&>::value>::type* = 0)
{
std::cout << "Register int func" << std::endl;
}
//A parameters
template <class T>
static void RegisterFunctor(const T& /*functor*/, typename std::enable_if<std::is_same<typename function_traits<T>::template argument<0>::type, const A&>::value>::type* = 0)
{
std::cout << "Register int func" << std::endl;
}
};
void intFunc(const int&) {}
void aFunc(const A&){}
int main(int /*argc*/, char */*argv*/[])
{
Functor<int> intFunctor;
Functor<A> aFunctor;
Register::RegisterFunctor(intFunctor);
Register::RegisterFunctor(&intFunc);
Register::RegisterFunctor(aFunctor);
Register::RegisterFunctor(&aFunc);
return 0;
}
if F is a std::functionyou should be able to use the its member type and check with `std::is_same':
template<class F>
void register_handler( F& f ) // any callable object
{
// find out T - the argument type of f
if(std::is_same<int, F::argument_type>::value)
{ .... }
//etc .....
}
An up and running example here
but that kind of code can quickly become a mess to maintain.
You could use sfinae and test if your argument is convertible to a std::function with the required arguments:
#include <type_traits>
#include <functional>
#include <iostream>
class A
{
};
template <class T>
struct Functor
{
void operator()(const T& t)
{}
};
struct Register
{
//int parameters
template <class T>
static void RegisterFunctor(const T& /*functor*/, typename std::enable_if<std::is_constructible<typename std::function<void (int)>, T>::value >::type* = 0)
{
std::cout << "Register int func" << std::endl;
}
//A parameters
template <class T>
static void RegisterFunctor(const T& /*functor*/, typename std::enable_if<std::is_constructible<typename std::function<void (A)>, T>::value >::type* = 0)
{
std::cout << "Register a func" << std::endl;
}
};
void intFunc(int) {}
void aFunc(A){}
int main(int /*argc*/, char */*argv*/[])
{
Functor<int> intFunctor;
Functor<A> aFunctor;
Register::RegisterFunctor(intFunctor);
Register::RegisterFunctor(&intFunc);
Register::RegisterFunctor(aFunctor);
Register::RegisterFunctor(&aFunc);
return 0;
}