SFINAE for callback registration - c++

I tried to use this trick to register callback if it exists check if member exists using enable_if:
template<class Callback>
class Foo
{
public:
Foo()
{barEventRegister(has_member{});}
private:
struct has_not_member{};
struct has_member:public has_not_member{};
template<class X> struct cb_test
{typedef int type;};
template<typename cb_test<decltype(&Callback::barEvent)>::type=0>
void barEventRegister(has_member)
{
//register callback for bar
}
void barEventRegister(has_member)
{
//do nothing
}
};
struct MyCallback
{
};
int main()
{
Foo<MyCallback> foo;
}
But I get
template<typename cb_test<decltype(&Callback::barEvent)>::type=0>
void barEventRegister(has_not_member)
error: 'barEvent' is not a member of 'MyCallback'
It appears that the invalid template is instantiated anyways. Is that because Callback is part of the class template, and not the registration routine?

Your SFINAE fails because it relies on the surrounding class type parameter. SFINAE only works on deduced type arguments, which are function type arguments the compiler tries to figure out based on the call.
A fix could look like:
template<class S = Callback, typename cb_test<decltype(S::barEvent)>::type=0>
void barEventRegister(has_member)
where the SFINAE is based on S, which the compiler will deduce rather then get explicitly.
Also, note that your second overload should take a has_not_member, not has_member. As it is now, it will always be chosen, even if the member exists, since non-template overloads are chosen when equivalent to template ones.

Related

Checking for a templated static method via concepts

I want to write a concept that checks if the type has a static method called foo. That method will have a templated parameter (the function will be called multiple times later with different parameter types).
Because of that templated parameter, it's quite difficult to check it. For the start, I thought I only check if there is a member at all with that name.
The following code compiles with Clang, but doesn't compile with GCC, because it cannot resolve the address of the overloaded function T::foo.
template <typename T>
concept HasFoo = requires { T::foo; };
class Bar {
public:
template <typename T>
static void foo(T t);
};
static_assert(HasFoo<Bar>);
How do you correctly check for the existence of a templated static method (working in Clang and GCC)?
And ideally, can you even check more than this? Like checking if the return type is void, or if it is callable.
One way would be to include the templated type into the concept, but as I want to use the method with multiple different types.
So checking with only one type, like in the following code, is not enough.
template <typename T, typename T2>
concept HasFoo = requires { T::template foo<T2>; };
static_assert(HasFoo<Bar, int>);
How do you correctly check for the existence of a templated static method (working in Clang and GCC)? And ideally, can you even check more than this? Like checking if the return type is void, or if it is callable.
I do have some constraints on template arguments, for the sake of the simplified example in the question we can just assume it's an integer type.
To check if the class support a static template method foo() that is callable with an integer and return void, you can simply check
template <typename T>
concept HasFoo = std::is_same_v<decltype(T::foo(0)), void>;
If you also want to be sure that the foo() method is a template one, I suppose you can also check that converting &T::foo to different function pointer types you get different values, so (for example)
( (void*)(&T::template foo<int>)
!= (void*)(&T::template foo<long>))
Combining the two requirements,
template <typename T>
concept HasFoo = ( (void*)(&T::template foo<int>)
!= (void*)(&T::template foo<long>))
&& std::is_same_v<decltype(T::foo(0)), void>;
With
struct Bar1
{ template <typename T> static void foo (T) {} };
struct Bar2
{ static void foo (int) {} };
struct Bar3
{ template <typename T> static T foo; };
template <typename T>
T Bar3::foo;
struct Bar4
{ template <typename T> static int foo (T) { return 0; } };
you have
static_assert(HasFoo<Bar1>);
static_assert(not HasFoo<Bar2>); // not because foo() isn't template
static_assert(not HasFoo<Bar3>); // not because foo isn't callable
static_assert(not HasFoo<Bar4>); // not becasue foo() return int

How can I use a nested type belonging to a templated class in another template function in C++?

I'm setting up a function that initializes tuples based on a tuple type and a functor struct For that has a size_t template argument INDEX to retain the compile-time index. This functor may also depend on other template arguments T.... Because of this the functors exist within other structures (TClass in this example) that hold these template arguments.
The initialization function (called Bar here) has a template<std::size_t> class template argument to ensure that the used class actually can store the index.
While the design I've come up with works fine when I call it from a non-template function, it does not compile if the template T2 of a function does determine the template parameter of the wrapper TClass.
Here is the definition of the functor For wrapped inside TClass:
#include <cstdlib>
template <typename T> struct TClass {
template<std::size_t INDEX> struct For {
void operator()() {}
};
};
And here are the function calls i want to use:
template <template<std::size_t> class FOR> void bar() {
//...
}
template <typename T> void foo() {
bar<TClass<T>::For>(); //Does not compile
}
int main() {
bar<TClass<int>::For>(); //Works
foo<int>();
return 0;
}
The compiler output for the faulty foo-call is:
error: dependent-name ‘TClass<T>::For’ is parsed as a non-type, but instantiation yields a type
Bar<TClass<T>::For>(); //Does not compile
I know that dependent type names usually have to be preceded by a typename but this is also not necessary for the first bar-call. I assumed it was because the template argument can only be interpreted as a type. So I thought that maybe typename would result in correct compilation but if I change foo to
template <typename T> void foo() {
bar<typename TClass<T>::For>(); //Does not compile
}
I get:
error: ‘typename TClass<int>::For’ names ‘template<long unsigned int INDEX> struct TClass<int>::For’, which is not a type
Bar<typename TClass<T>::For>(); //Does not compile
I've also come up with a design where the ()-operator of TClass depends on the template INDEX which also works fine because it is not necessary to use nested types anymore. It looks like this:
#include <cstdlib>
template <typename T> struct TClass {
template<std::size_t INDEX> void operator()() {}
};
template <typename FOR> void bar() {
//...
}
template <typename T> void foo() {
bar<TClass<T>>(); //Does compile
}
Apparently it is not possible to use dependent type names in functions where the template of the type is determined by the function's template parameters, but why? And how do I implement this correctly? To make writing future type checks with type traits easier I would prefer it if I can use a functor.
The compiler cannot know that TClass<T>::For refers to a template at the first stage of template instantiation. It needs a bit of help with template keyword. Fix:
template <typename T> void foo() {
bar<TClass<T>::template For>();
}

Compile time deduction of template member function

Is it possible to get the return type of a template member function at compile time?
I guess I need something along the lines of:
template<class T>
struct SomeClass
{
// T must have a function foo(int), but do not know the
// return type, it could be anything
using RType = ??? T::foo(int) ???; // Is it possible to deduce it here?
}
What you want to do can be achieved by using the decltype operator together with the std::declval template.
decltype(EXPRESSION) yields – at compile time – the type that EXPRESSION would have. The EXPRESSION itself is never evaluated. This is much like sizeof(EXPRESSION) returns the size of whatever EXPRESSION evaluates to without ever actually evaluating it.
There is only one problem: Your foo is a non-static member function so writing decltype(T::foo(1)) is an error. We somehow need to obtain an instance of T. Even if we know nothing about its constructor, we can use std::declval to obtain a reference to an instance of it. This is a purely compile-time thing. std::declval is actually never defined (only declared) so don't attempt to evaluate it at run-time.
Here is how it would look together.
#include <type_traits>
template <typename SomeT>
struct Something
{
using RetT = decltype(std::declval<SomeT>().foo(1));
};
To see that it actually works, consider this example.
struct Bar
{
float
foo(int);
};
struct Baz
{
void
foo(int);
};
int
main()
{
static_assert(std::is_same<float, Something<Bar>::RetT>::value, "");
static_assert(std::is_same<void, Something<Baz>::RetT>::value, "");
}
While this does what I think you have asked for, it is not ideal in the sense that if you attempt to instantiate Something<T> with a T that doesn't have an appropriate foo member, you'll get a hard compiler error. It would be better to move the type computation into the template arguments such that you can benefit from the SFINAE rule.
template <typename SomeT,
typename RetT = decltype(std::declval<SomeT>().foo(1))>
struct Something
{
// Can use RetT here ...
};
If you know the argument types to your function call the following should work:
template<typename T>
struct X
{
typedef typename decltype(std::declval<T>.foo(std::declval<int>())) type;
};
If you don't you can still deduce the type of the function pointer and extract the return type:
template<class F>
struct return_type;
template<class C, class R, class... Args>
struct return_type<R(C::*)(Args...)>
{ using type = R; };
template<typename T>
struct X
{
typedef typename return_type<decltype(&T::foo)>::type type;
};
This will fail if T::foo is an overloaded function or member of T.
Unfortunately it is only possible to know the return type of some expression if you know with what arguments you are going to call it (which, unfortunately, often is a different place from where you need to know the return type)...

How to deduce class type from method type in C++ templates?

In templates as shown below, I would like the call Run(&Base::foo) succeed without the need to name the Base type twice (as is done in the compiling Run<Base>(&Base::foo) call). Can I have that? Possibly without adding a ton of Boost headers?
With the provided code, I get an error of:
prog.cpp:26: error: no matching function for call to ‘Run(bool (Base::*)())’
(you can fiddle with the snippet at http://ideone.com/8NZkq):
#include <iostream>
class Base {
public:
bool foo() { return true; }
};
Base* x;
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<typename T>
void Run(typename Traits<T>::BoolMethodPtr check) {
T* y = dynamic_cast<T*>(x);
std::cout << (y->*check)();
}
int main() {
Base y;
x = &y;
Run<Base>(&Base::foo);
Run(&Base::foo); // why error?
}
The T in Traits<T>::BoolMethodPtr is in a non-deduced context, so the compiler will not deduce automatically from the call what type T should be.
This is because there could be code like this:
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<>
struct Traits<int> {
typedef bool (Base::*BoolMethodPtr)();
};
Run(&Base::foo); /* What should T be deduced to? Base and int are both equally possible */
If you can do without the Traits<T> class, you can write Run as:
template<class Class>
void Run(bool (Class::*check)()) {
Class* y = dynamic_cast<Class*>(x);
std::cout << (y->*check)();
}
In this context, Class can be deduced to mean Base
To pick apart a type, any type, use partial specialization. There is no function template partial specialization, so you'll need to directly parameterize the function on its argument type and retrieve the class type inside.
template< typename T >
struct get_host_class; // most types are not ptmfs: don't implement this
template< typename C >
struct get_host_class< bool (C::*)() > { // implement partial specialization
typedef C host;
typedef void sfinae; // disallow function for non ptmf arguments
};
template< typename T >
typename get_host_class<T>::sfinae Run( T check) {
typedef T BoolMethodPtr; // or something
typedef typename get_host_class< T >::host host;
}
I think this is a non deduced context.
$14.8.2.5/5- "The non-deduced contexts
are: — The nested-name-specifier of a
type that was specified using a
qualified-id."
I think this is the quote that applies in this case. But some template gods need to ratify my understanding.
When the compiler tries to match a template argument, it only considers the primary class type. In other words, when it encounters the expression:
Run(&Base::foo);
...and it's trying to figure out the template parameter for Run, it only considers the type of foo itself, and doesn't consider whatever class foo is a part of.
EDIT:
And the type of foo is bool(Base::*)(void), but what you want the compiler to find is just Base

How to pass a method pointer as a template parameter

I am trying to write a code that calls a class method given as template parameter. To simplify, you can suppose the method has a single parameter (of an arbitrary type) and returns void. The goal is to avoid boilerplate in the calling site by not typing the parameter type. Here is a code sample:
template <class Method> class WrapMethod {
public:
template <class Object>
Param* getParam() { return &param_; }
Run(Object* obj) { (object->*method_)(param_); }
private:
typedef typename boost::mpl::at_c<boost::function_types::parameter_types<Method>, 1>::type Param;
Method method_;
Param param_
};
Now, in the calling site, I can use the method without ever writing the type of the parameter.
Foo foo;
WrapMethod<BOOST_TYPEOF(&Foo::Bar)> foo_bar;
foo_bar.GetParam()->FillWithSomething();
foo_bar.Run(foo);
So, this code works, and is almost what I want. The only problem is that I want to get rid of the BOOST_TYPEOF macro call in the calling site. I would like to be able to write something like WrapMethod<Foo::Bar> foo_bar instead of WrapMethod<BOOST_TYPEOF(&Foo::Bar)> foo_bar.
I suspect this is not possible, since there is no way of referring to a method signature other than using the method signature itself (which is a variable for WrapMethod, and something pretty large to type at the calling site) or getting the method pointer and then doing typeof.
Any hints on how to fix these or different approaches on how to avoid typing the parameter type in the calling site are appreciated.
Just to clarify my needs: the solution must not have the typename Param in the calling site. Also, it cannot call FillWithSomething from inside WrapMethod (or similar). Because that method name can change from Param type to Param type, it needs to live in the calling site. The solution I gave satisfies both these constraints, but needs the ugly BOOST_TYPEOF in the calling site (using it inside WrapMethod or other indirection would be fine since that is code my api users won't see as long as it is correct).
Response:
As far as I can say, there is no possible solution. This boil down to the fact that is impossible to write something like WrapMethod<&Foo::Bar>, if the signature of Bar is not known in advance, even though only the cardinality is necessary. More generally, you can't have template parameters that take values (not types) if the type is not fixed. For example, it is impossible to write something like typeof_literal<0>::type which evalutes to int and typeof_literal<&Foo::Bar>::type, which would evaluate to void (Foo*::)(Param) in my example. Notice that neither BOOST_TYPEOF or decltype would help because they need to live in the caling site and can't be buried deeper in the code. The legitimate but invalid syntax below would solve the problem:
template <template<class T> T value> struct typeof_literal {
typedef decltype(T) type;
};
In C++0x, as pointed in the selected response (and in others using BOOST_AUTO), one can use the auto keyword to achieve the same goal in a different way:
template <class T> WrapMethod<T> GetWrapMethod(T) { return WrapMethod<T>(); }
auto foo_bar = GetWrapMethod(&Foo::Bar);
Write it as:
template <typename Object, typename Param, void (Object::*F)(Param)>
class WrapMethod {
public:
Param* getParam() { return &param_; }
void Run(Object* obj) { (obj->*F)(param_); }
private:
Param param_;
};
and
Foo foo;
WrapMethod<Foo, Param, &Foo::Bar> foo_bar;
foo_bar.getParam()->FillWithSomething();
foo_bar.Run(foo);
EDIT: Showing a template function allowing to do the same thing without any special template wrappers:
template <typename Foo, typename Param>
void call(Foo& obj, void (Foo::*f)(Param))
{
Param param;
param.FillWithSomthing();
obj.*f(param);
}
and use it as:
Foo foo;
call(foo, &Foo::Bar);
2nd EDIT: Modifying the template function to take the initialization function as a parameter as well:
template <typename Foo, typename Param>
void call(Foo& obj, void (Foo::*f)(Param), void (Param::*init)())
{
Param param;
param.*init();
obj.*f(param);
}
and use it as:
Foo foo;
call(foo, &Foo::Bar, &Param::FillWithSomething);
If your compiler supports decltype, use decltype:
WrapMethod<decltype(&Foo::Bar)> foo_bar;
EDIT: or, if you really want to save typing and have a C++0x compliant compiler:
template <class T> WrapMethod<T> GetWrapMethod(T) { return WrapMethod<T>(); }
auto foo_bar= GetWrapMethod(&Foo::Bar);
EDIT2: Although, really, if you want it to look pretty you either have to expose users to the intricacies of the C++ language or wrap it yourself in a preprocessor macro:
#define WrapMethodBlah(func) WrapMethod<decltype(func)>
Have you considered using method templates?
template <typename T> void method(T & param)
{
//body
}
Now the compiler is able to implicitly determine parameter type
int i;
bool b;
method(i);
method(b);
Or you can provide type explicitly
method<int>(i);
You can provide specializations for different data types
template <> void method<int>(int param)
{
//body
}
When you are already allowing BOOST_TYEPOF(), consider using BOOST_AUTO() with an object generator function to allow type deduction:
template<class Method> WrapMethod<Method> makeWrapMethod(Method mfp) {
return WrapMethod<Method>(mfp);
}
BOOST_AUTO(foo_bar, makeWrapMethod(&Foo::Bar));
Okay let's have a go at this.
First of all, note that template parameter deduction is available (as noted in a couple of answers) with functions.
So, here is an implementation (sort of):
// WARNING: no virtual destructor, memory leaks, etc...
struct Foo
{
void func(int e) { std::cout << e << std::endl; }
};
template <class Object>
struct Wrapper
{
virtual void Run(Object& o) = 0;
};
template <class Object, class Param>
struct Wrap: Wrapper<Object>
{
typedef void (Object::*member_function)(Param);
Wrap(member_function func, Param param): mFunction(func), mParam(param) {}
member_function mFunction;
Param mParam;
virtual void Run(Object& o) { (o.*mFunction)(mParam); }
};
template <class Object, class Param>
Wrap<Object,Param>* makeWrapper(void (Object::*func)(Param), Param p = Param())
{
return new Wrap<Object,Param>(func, p);
}
int main(int argc, char* argv[])
{
Foo foo;
Wrap<Foo,int>* fooW = makeWrapper(&Foo::func);
fooW->mParam = 1;
fooW->Run(foo);
Wrapper<Foo>* fooW2 = makeWrapper(&Foo::func, 1);
fooW2->Run(foo);
return 0;
}
I think that using a base class is the native C++ way of hiding information by type erasure.