compile-time conditional member function call in C++ - c++

I have a template class for which certain member functions only make sense if the template parameters satisfy certain conditions. Using, for instance, std::enable_if<> I can define them only for these cases, but how can I call them conditionally? Here is a brief example
template<class T> class A
{
typename std::enable_if<std::is_floating_point<T>::value>::type a_member();
void another_member()
{
a_member(); // how to restrict this to allowed cases only?
}
};

Firstly, you can't use SFINAE like that - the template type parameter needs to be on the function, not the class.
A full solution looks like this:
template<class T> class A
{
private:
template <class S>
typename std::enable_if<std::is_floating_point<S>::value>::type a_member() {
std::cout << "Doing something";
}
template <class S>
typename std::enable_if<!std::is_floating_point<S>::value>::type a_member() {
//doing nothing
}
public:
void another_member()
{
a_member<T>();
}
};
int main() {
A<int> AInt;
AInt.another_member();//doesn't print anything
A<float> AFloat;
AFloat.another_member();//prints "Doing something"
}

WARNING: This is a complete, terrible hack that I have not tried that may never work.
Try adding this to the class declaration:
typename std::enable_if<std::is_floating_point<T>, int*>::type a_enabled_p() { return 0;};
void another()
{
if((a_enabled_p()+1)==1)
{
//Not enabled
}
else if((a_enabled_p()+1)==sizeof(int))
{
//Is enabled
}
}
Here's why this horror might work. If they are floating point, the return value of the predicate is an int*. If they are, there is no typedef, and it defaults to int (I hope). When you add 1 to an int*, you are really adding sizeof(int). Adding 1 to an int increments by one. That means that by checking the value of adding one, we know.
Note: Don't use this. It was fun to come up with, but the above answer is MUCH, MUCH
MUCH
Better. Don't use this. Please.

Related

Why does C++20 not allow a concept declared nested in a class? [duplicate]

Consider this code:
struct A
{
template <typename T>
concept foo = true;
};
It doesn't compile. My Clang 10 gives me error: concept declarations may only appear in global or namespace scope, and GCC says something similar.
Is there a reason why it's not allowed? I don't see why it couldn't work, even if the enclosing class was a template.
The fundamental difficulty that would arise is that concepts could become dependent:
template<class T>
struct A {
template<T::Q X>
void f();
};
Is X a non-type template parameter of (dependent) type T::Q (which does not require typename in C++20), or is it a type template parameter constrained by the concept T::Q?
The rule is that it’s the former; we would need new syntax (along the lines of typename/template) to express the other possibility: perhaps something like
template<T::concept Q X> requires T::concept R<X*>
void A::g() {}
No one has explored such an extension seriously, and it could easily conflict with other extensions to concept syntax that might be more valuable.
The why is discussed in the answer by #DavisHerring. In this answer I want to share a pattern I was actually looking for when I encountered this question.
Depending on your use case, you maybe don't need the concept definition. If all you want to do is to avoid SFINAE trickery, you can directly invoke the requires clause and get rid of any concept at class scope:
struct A
{
template<typename T>
auto operator()(T t) const
{
if constexpr(requires { t.foo(); })
{
std::cout<<"foo"<<std::endl;
}
else
{
std::cout<<"no foo"<<std::endl;
}
}
};
and use that as
struct B { auto foo() {} };
struct C {};
int main()
{
A a;
a(B()); //prints "foo"
a(C()); //prints "no foo"
}
DEMO
However, if you find yourself using the same requires statement multiple times in your class, the original question why you just can't declare it once at class scope is justified.
Thus, in order to work around code duplication, you can declare a single static function which contains the concept you are looking for, e.g.
struct A
{
template<typename T>
static constexpr auto concept_foo(T t)
{
return requires{ t.foo(); };
}
template<typename T>
auto operator()(T t) const
{
if constexpr(concept_foo(t))
{
std::cout<<"foo"<<std::endl;
}
else
{
std::cout<<"no foo"<<std::endl;
}
}
};
This pattern could replace most use cases for concepts at class scope.

Is it possible to supply template parameters when calling operator()?

I'd like to use a template operator() but am not sure if it's possible. Here is a simple test case that won't compile. Is there something wrong with my syntax, or is this simply not possible?
struct A {
template<typename T> void f() { }
template<typename T> void operator()() { }
};
int main() {
A a;
a.f<int>(); // This compiles.
a.operator()<int>(); // This compiles.
a<int>(); // This won't compile.
return 0;
}
Like chris mentioned in the comments, no, not with the shorthand syntax. You must use the full .operator()<T>() syntax;
If you really want to use templated operator() and want to avoid writing constructions like a.operator()<int>(); you can add an auxiliary parameter to it:
template <typename T>
struct type{};
struct A
{
template<typename T>
void operator()(type<T>) { }
};
int main()
{
A a;
a(type<int>());
}
Live demo.
In C++14 you can even omit empty brackets in a(type<int>()); via a variable template:
template <typename T>
struct type_{};
template <typename T>
constexpr type_<T> type{};
struct A
{
template<typename T>
void operator()(type_<T>) { }
};
int main()
{
A a;
a(type<int>);
}
Live demo.
The exact syntax you want to use is not possible in the C++ language.
Depending on the real problem you're trying to solve (which isn't in the question), I can think of at least three options:
Use a named function instead of the operator.
Template A instead of the operator itself.
Use the verbose spelling to call the operator() (I'm not a big fan of this option).

"What happened to my SFINAE" redux: conditional template class members?

I'm new to writing template metaprogramming code (vs. just reading it). So I'm running afoul of some noob issues. One of which is pretty well summarized by this non-SO post called "What happened to my SFINAE?", which I will C++11-ize as this:
(Note: I gave the methods different names only to help with my error diagnosis in this "thought experiment" example. See #R.MartinhoFernandes's notes on why you wouldn't actually choose this approach in practice for non-overloads.)
#include <type_traits>
using namespace std;
template <typename T>
struct Foo {
typename enable_if<is_pointer<T>::value, void>::type
valid_if_pointer(T) const { }
typename disable_if<is_pointer<T>::value, void>::type
valid_if_not_pointer(T) const { }
};
int main(int argc, char * argv[])
{
int someInt = 1020;
Foo<int*>().valid_if_pointer(&someInt);
Foo<int>().valid_if_not_pointer(304);
return 0;
}
#Alf says what happened to the SFINAE is "It wasn't there in the first place", and gives a suggestion that compiles, but templates the functions instead of the class. That might be right for some situations, but not all. (For instance: I'm specifically trying to write a container that can hold types that may or may not be copy-constructible, and I need to flip methods on and off based on that.)
As a workaround, I gave this a shot...which appears to work correctly.
#include <type_traits>
using namespace std;
template <typename T>
struct FooPointerBase {
void valid_if_pointer(T) const { }
};
template <typename T>
struct FooNonPointerBase {
void valid_if_not_pointer(T) const { }
};
template <typename T>
struct Foo : public conditional<
is_pointer<T>::value,
FooPointerBase<T>,
FooNonPointerBase<T> >::type {
};
int main(int argc, char * argv[])
{
int someInt = 1020;
#if DEMONSTRATE_ERROR_CASES
Foo<int*>().valid_if_not_pointer(&someInt);
Foo<int>().valid_if_pointer(304);
#else
Foo<int*>().valid_if_pointer(&someInt);
Foo<int>().valid_if_not_pointer(304);
#endif
return 0;
}
But if this is not broken (is it?), it's certainly not following a good general methodology for how to turn on and off methods in a templated class based on sniffing the type for traits. Is there a better solution?
Firstly, C++11 did not carry forward boost's disable_if. So if you're going to transition boost code, you'll need to use enable_if with a negated condition (or redefine your own disable_if construct).
Secondly, for SFINAE to reach in and apply to the method level, those methods must be templates themselves. Yet your tests have to be done against those templates' parameters...so code like enable_if<is_pointer<T> will not work. You can finesse this by making some template argument (let's say X) default to be equal to T, and then throw in a static assertion that the caller has not explicitly specialized it to something else.
This means that instead of writing:
template <typename T>
struct Foo {
typename enable_if<is_pointer<T>::value, void>::type
valid_if_pointer(T) const { /* ... */ }
typename disable_if<is_pointer<T>::value, void>::type
valid_if_not_pointer(T) const { /* ... */ }
};
...you would write:
template <typename T>
struct Foo {
template <typename X=T>
typename enable_if<is_pointer<X>::value, void>::type
valid_if_pointer(T) const {
static_assert(is_same<X,T>::value, "can't explicitly specialize");
/* ... */
}
template <typename X=T>
typename enable_if<not is_pointer<X>::value, void>::type
valid_if_not_pointer(T) const {
static_assert(is_same<X,T>::value, "can't explicitly specialize");
/* ... */
}
};
Both are now templates and the enable_if uses the template parameter X, rather than T which is for the whole class. It's specifically about the substitution that happens whilst creating the candidate set for overload resolution--in your initial version there's no template substitution happening during the overload resolution.
Note that the static assert is there to preserve the intent of the original problem, and prevent someone being able to compile things like:
Foo<int>().valid_if_pointer<int*>(someInt);
The way I see it you don't want SFINAE here. SFINAE is useful to pick between different templated overloads. Basically, you use it to help the compiler pick between template <typename Pointer> void f(Pointer); and template <typename NotPointer> void f(NotPointer);.
That's not what you want here. Here, you have two functions with different names, not two overloads of the same. The compiler can already pick between template <typename Pointer> void f(Pointer); and template <typename NotPointer> void g(NotPointer);.
I'll give an example to explain why I think SFINAE is not only unnecessary, but undesirable here.
Foo<int> not_pointer;
Foo<int*> pointer;
not_pointer.valid_if_pointer(); // #1
not_pointer.valid_if_not_pointer(); // #2
pointer.valid_if_pointer(); // #3
pointer.valid_if_not_pointer(); // #4
Now, let's say you managed to get this working with SFINAE. Attempting to compile this piece of code will yield errors on lines #1 and #4. Those errors will be something along the lines of "member not found" or similar. It may even list the function as a discarded candidate in overload resolution.
Now, let's say you didn't do this with SFINAE, but with static_assert instead. Like this:
template <typename T>
struct Foo {
void valid_if_pointer(T) const {
static_assert(std::is_pointer<T>::value, "valid_if_pointer only works for pointers");
// blah blah implementation
}
void valid_if_not_pointer(T) const {
static_assert(!std::is_pointer<T>::value, "valid_if_not_pointer only works for non-pointers");
// blah blah implementation
}
};
With this you'll get errors on the same line. But you'll get extremely short and useful errors. Something people have been asking of compiler writers for years. And it's now at your doorstep :)
You get the same thing: errors on both cases, except you get a much better one without SFINAE.
Also note that, if you didn't use static_assert at all and the implementation of the functions was only valid if given pointers or non-pointers, respectively, you would still get errors on the appropriate lines, except maybe nastier ones.
TL;DR: unless you have two actual template functions with the same name, it's preferable to use static_assert instead of SFINAE.

Switch passed type from template

Is it possible in C++ to check the type passed into a template function? For example:
template <typename T>
void Foo()
{
if (typeof(SomeClass) == T)
...;
else if (typeof(SomeClass2) == T)
...;
}
Yes, it is...but it probably won't work the way you expect.
template < typename T >
void foo()
{
if (is_same<T, SomeClass>::value) ...;
else if (is_same<T, SomeClass2>::value) ...;
}
You can get is_same from std:: or boost:: depending on your desire/compiler. The former is only in C++0x.
The problem comes with what is in .... If you expect to be able to make some function call specific to those types within foo, you are sadly mistaken. A compiler error will result even though that section of code is never run when you pass in something that doesn't obey that expected interface.
To solve THAT problem you need to do something a bit different. I'd recommend tag dispatching:
struct v1_tag {};
struct v2_tag {};
template < typename T > struct someclass_version_tag;
template < > struct someclass_version_tag<SomeClass> { typedef v1_tag type; };
template < > struct someclass_version_tag<SomeClass2> { typedef v2_tag type; };
void foo(v1_tag) { ... }
void foo(v2_tag) { ... }
template < typename T > void foo()
{
typedef typename someclass_version_tag<T>::type tag;
foo(tag());
}
Note that you will not be suffering any runtime-polymorphism overhead here and with optimizations turned on it should result in the same or even smaller code size AND speed (though you shouldn't be worrying about that anyway until you've run a profiler).
If you want to do something specific based on the type, specialize the template:
template <typename T>
void Foo() { }
template <>
void Foo<SomeClass>() { }
template <>
void Foo<SomeClass2>() { }
// etc.
(You don't actually want to specialize the function template, though; this is for exposition only. You'll either want to overload the template if you can, or delegate to a specialized class template. For more on why and how to avoid specializing function templates, read Herb Sutter's Why Not Specialize Function Templates?)
No, however you can use partial specialization :
template<typename T>
struct Bar { static void foo(); };
template<typename T>
template<> inline void Bar<T>::foo() {
//generic
}
template<> inline void Bar<int>::foo() {
//stuff for int
}
template<> inline void Bar<QString>::foo() {
//QString
}
Edit Yes with type traits, however it's not really needed.
Edit 2 type_traits example.
#include <type_traits>
template<typename T> void foo() {
using std::is_same;
if (is_same<T, T2>::value || is_same<T, T1>::value) {
/* stuff */
}
}
Yes. You will have to use type traits. For example:
#include <boost/type_traits/is_same.hpp>
template <typename T>
void Foo ()
{
if ((boost::is_same<T, SomeClass>::value))
...;
else if ((boost::is_same<T, SomeClass2>::value))
...;
}
Depending on what you are trying to achieve, using template specialization might be much better choice.
Also, you can use enable_if/disable_if to conditionally enable/disable certain functions/methods. Combining this with type traits will allow, for example, using one function for one set of types and another function for another set of types.

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.