const/non-const member function based on compile time conditions - c++

Let's consider following classes:
struct InputArgument{};
struct SpecialInputArgument{};
struct MoreSpecialInputArgument{};
struct OutputArgument{};
struct SpecialOutputArgument{};
struct MoreSpecialOutputArgument{};
I need to have a member function that accepts all previous classes as arguments and act on them. To simplify the implementation (don't repeat same code over and over) I made the member function template and dispatched the actual code to non-member functions:
template<typename T>
typename std::enable_if<std::is_fundamental<T>::value>::type DoSomething(T&, const InputArgument&)
{
}
template<typename T>
typename std::enable_if<std::is_fundamental<T>::value>::type DoSomething(const T&, OutputArgument&)
{
}
template<typename T>
typename std::enable_if<std::is_fundamental<T>::value>::type DoSomething(T&, const SpecialInputArgument&)
{
}
template<typename T>
typename std::enable_if<std::is_fundamental<T>::value>::type DoSomething(const T&, SpecialOutputArgument&)
{
}
template<typename T>
typename std::enable_if<std::is_fundamental<T>::value>::type DoSomething(T&, const MoreSpecialInputArgument&)
{
}
template<typename T>
typename std::enable_if<std::is_fundamental<T>::value>::type DoSomething(const T&, MoreSpecialOutputArgument&)
{
}
struct MyGloriuosClass
{
template<typename T>
void DoSomething(T& arg)
{
::DoSomething(myIntMember, arg);
::DoSomething(myFloatMember, arg);
}
int myIntMember = 0;
float myFloatMember = 0.f;
};
And this works perfect:
MyGloriuosClass myGloriuosObject;
InputArgument inputArgument;
SpecialInputArgument specialInputArgument;
MoreSpecialInputArgument moreSpecialInputArgument;
OutputArgument outputArgument;
SpecialOutputArgument specialOutputArgument;
MoreSpecialOutputArgument moreSpecialOutputArgument;
myGloriuosObject.DoSomething(inputArgument);
myGloriuosObject.DoSomething(specialInputArgument);
myGloriuosObject.DoSomething(moreSpecialInputArgument);
myGloriuosObject.DoSomething(outputArgument);
myGloriuosObject.DoSomething(specialOutputArgument);
myGloriuosObject.DoSomething(moreSpecialOutputArgument);
Expect in one case, when the object I use is const:
const MyGloriuosClass myConstGloriousObject = MyGloriuosClass();
myConstGloriousObject.DoSomething(outputArgument);
myConstGloriousObject.DoSomething(specialOutputArgument);
myConstGloriousObject.DoSomething(moreSpecialOutputArgument);
As you can see, all the actual code is done in functions that accept const objects when the argument is of type Output so there is no reason to limit this to only non-const objects or to write my member function twice, once as const and once as non-const. In my ideal world I will deduce if the function is const/non-const based on the type trait std::is_base_of of the argument, but I don't know if this is possible or not.
Is it possible to declare a member function const/non-const based on compile time conditions?

A member function is either const, or non-const member function. There is no third option. Classes can define either a const function, a non-const function, or even both, as you know.
What I suspect that you might be missing is that a const member function can be invoked for a non-const class instance.
So, if your member function does not need to modify any other members of the class instance, just declare your member function as a const function, and it can be invoked for either a const or a non-const class instance.

Related

avoid pointer-to-member-function for non-class type

I am writing a kind of container class, for which I would like to offer an apply method which evaluates a function on the content of the container.
template<typename T>
struct Foo
{
T val;
/** apply a free function */
template<typename U> Foo<U> apply(U(*fun)(const T&))
{
return Foo<U>(fun(val));
}
/** apply a member function */
template<typename U> Foo<U> apply(U (T::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
struct Bar{};
template class Foo<Bar>; // this compiles
//template class Foo<int>; // this produces an error
The last line yields error: creating pointer to member function of non-class type ‘const int’. Even though I only instantiated Foo and not used apply at all. So my question is: How can I effectively remove the second overload whenever T is a non-class type?
Note: I also tried having only one overload taking a std::function<U(const T&)>. This kinda works, because both function-pointers and member-function-pointers can be converted to std::function, but this approach effectively disables template deduction for U which makes user-code less readable.
Using std::invoke instead helps, it is much easier to implement and read
template<typename T>
struct Foo
{
T val;
template<typename U> auto apply(U&& fun)
{
return Foo<std::invoke_result_t<U, T>>{std::invoke(std::forward<U>(fun), val)};
}
};
struct Bar{};
template class Foo<Bar>;
template class Foo<int>;
However, this won't compile if the functions are overloaded
int f();
double f(const Bar&);
Foo<Bar>{}.apply(f); // Doesn't compile
The way around that is to use functors instead
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return f(decltype(bar)(bar)); });
Which also makes it more consistent with member function calls
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return decltype(bar)(bar).f(); });
In order to remove the second overload you'd need to make it a template and let SFINAE work, e. g. like this:
template<typename T>
struct Foo
{
T val;
//...
/** apply a member function */
template<typename U, typename ObjT>
Foo<U> apply(U (ObjT::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
Alternatively, you could remove the second overload altogether, and use lambda or std::bind:
#include <functional> // for std::bind
template<typename T>
struct Foo
{
T val;
/** apply a member function */
template<typename U, typename FuncT>
Foo<U> apply(FuncT&& f)
{
return {f(val)};
}
};
struct SomeType
{
int getFive() { return 5; }
};
int main()
{
Foo<SomeType> obj;
obj.apply<int>(std::bind(&SomeType::getFive, std::placeholders::_1));
obj.apply<int>([](SomeType& obj) { return obj.getFive(); });
}
How can I effectively remove the second overload whenever T is a non-class type?
If you can use at least C++11 (and if you tried std::function I suppose you can use it), you can use SFINAE with std::enable_if
template <typename U, typename V>
typename std::enable_if<std::is_class<V>{}
&& std::is_same<V, T>{}, Foo<U>>::type
apply(U (V::*fun)() const)
{ return Foo<U>((val.*fun)()); }
to impose that T is a class.
Observe that you can't check directly T, that is a template parameter of the class, but you have to pass through a V type, a template type of the specific method.
But you can also impose that T and V are the same type (&& std::is_same<V, T>{}).

Choosing type based on lambda signature

I am trying to determine a type based on the signature of a lambda expression.
I've come up with the following code, which works, but I'm wondering if there isn't a simpler way to go about it. I've posted a full working example on ideone.
template <typename T_Callback>
class CallbackType {
private:
template <typename T>
static CallbackFunctionA<T> testlambda(void (T::*op)(A const &) const);
template <typename T>
static CallbackFunctionB<T> testlambda(void (T::*op)(B const &) const);
template <typename T>
static decltype(testlambda<T>(&T::operator())) testany(int);
template <typename T>
static T &testany(...);
public:
typedef decltype(testany<T_Callback>(0)) type;
};
In short, T_Callback can be either:
a lambda of the form [](A const &) { }
a lambda of the form [](B const &) { }
an instance of the class Callback or a class derived therefrom
It T_Callback is a lambda, a wrapper class derived from Callback should be returned (CallbackFunctionA or CallbackFunctionB), otherwise a reference to the callback type itself should be returned.
As I said the above code works just fine, but I'm wondering if it can be simplified, i.e. by removing the need for both testany and testlambda functions.
What you say you want:
a lambda of the form [](A const &) { } shall be mapped to CallbackFuncionA
a lambda of the form [](B const &) { } shall be mapped to CallbackFunctionB
an instance of the class Callback or a class derived therefrom shall be mapped to itself
What you actually have:
A functor having exactly one operator() returning nothing and having one argument of type const A& will be mapped to CallbackFunctionA
A functor having exactly one operator() returning nothing and having one argument of type const B& will be mapped to CallbackFunctionB
Anything else will be mapped to itself
My suggestion: Define a simple forwarder like this, for invoking when possible:
template<class X, class ARG...>
static auto may_invoke(const X& x, ARG&&... arg)
-> decltype(x(std::forward<ARG>(arg)...))
{ return x(std::forward<ARG>(arg)...); }
struct not_invoked {};
template<class X>
constexpr static not_invoked may_invoke(const X&, ...)
{ return {}; }
Also, a tester whether it can be invoked is nice to have:
template<class X, class ARG...>
constexpr bool does_invoke(const X& x, ARG&&... arg)
{ return !std::is_same<not_invoked,
decltype(may_invoke(x, std::forward<ARG>(arg)...))>::value; }
That allows you to at the same time make your code more general and the tests more stringent.
According to your specs, you need:
one step to differentiate (lambda) classes with one defined member operator() from classes derived from Callback (that apparently are assumed not to have exactly one member operator()), for which usage of SFINAE is the appropriate technique (impl with testany).
and another step to differentiate between the different argument types (A and B) of the found member operator (impl with testlamda).
Combining these steps in one would require both accessing the operator() in the call to testany from typedef test as well as resolving if such member function exists, which seems impossible to me.

How to remove const qualifier from a member function pointer

I'm using a library which contains the following code:
template <typename M>
void _register_member(lua_State *state,
const char *member_name,
M T::*member) {
std::function<M(T*)> lambda_get = [member](T *t) {
//^ error here
return t->*member;
};
//...
However this code does not accept const member function pointers. Passing those yields the error Function cannot return function type 'void () const' or whatever the type of the const member function is.
How do I remove the const qualifier from the passed member function or how do I apply std::remove_const?
As Adam S noted in comments this error occurs when he tries to compile this simple code which uses the library Selene:
#include <selene.h>
class C {
public:
bool get() const;
};
bool C::get() const {return true;}
int main() {
sel::State state;
state["C"].SetClass<C>("get", &C::get);
}
The compiler fails to compile the code in Class.h header. There are two overloads of function member _register_member of the class Class in it:
template <typename T,
typename A,
typename... Members>
class Class : public BaseClass {
private:
// ...
template <typename M>
void _register_member(lua_State *state,
const char *member_name,
M T::*member) {
// ...
}
template <typename Ret, typename... Args>
void _register_member(lua_State *state,
const char *fun_name,
Ret(T::*fun)(Args...)) {
// ...
}
// ...
};
The compiler can't choose the second overload when a pointer to a const function member is passed as a third argument. There should be another overload which could accept a const function member. It should be declared as follows:
template <typename Ret, typename... Args>
void _register_member(lua_State *state,
const char *fun_name,
Ret(T::*fun)(Args...) const)
^^^^^
Without such overload the compiler chooses the first overload which is created to work with pointers to data members (not function members) and fails to compile its code.
So you can't deal with const function members when using current version of Selena library (in such way as you do it at least).
I should mention that for those viewing this now, this was in fact a bug in my code (an oversight really) and it was fixed shortly after the problem was identified.

How does this C++ template member function declaration work?

Here is a snippet from the documentation of the Boost.Reflect library:
template<typename T>
struct xml_printer {
xml_printer( const T& c ):self(c){}
template<typename Type>
static xml_printer<Type> make( const Type& t ) {
return xml_printer<Type>(t);
}
template<typename Member, typename Class, Member Class::*p>
void operator()( const char* name )const {
std::cerr<<"<"<<name<<">"<<(self.*p)<<"</"<<name<<">\n";
}
const T& self;
};
The part I'm confused about is the declaration of operator() in the visitor:
template<typename Member, typename Class, Member Class::*p>
void operator()( const char* name )const
Particularly the Member Class::*p part. If I understand correctly, this type parameter is in place in order for the visitor to be able to resolve the member, and this is the type information which the library stores somehow for the member. However, it looks very unusual to me with two types written after each other. Could you explain to me how this works or perhaps provide an example that would call a function with such declaration?
Member Class::*p it's pointer to member of class Class with type Member.
So, something like this will call it's true
auto printer = xml_printer<T>();
printer.template operator()<int, T, &T::x>("x");
where x is member variable of type T with type int.
From docs, that you link
#define BOOST_REFLECT_VISIT_MEMBER( r, visitor, elem ) \
visitor.template operator()
<BOOST_TYPEOF(type::elem),type,&type::elem>( BOOST_PP_STRINGIZE(elem) );
Member Class::*p means that p is a pointer to Class member of type Member.
It's unrelated to template declarations, it's just a C++ syntax for pointer-to-member declaration.
Pointer to members are valid template arguments (see C++11 standard 14.1/4).
You'd call it like this:
xml_printer<foo> printer;
printer.operator()<some_type, foo, &foo::bar>("some string literal");

Invoke a may not existed member function by template

How can I call a may-existing member function by template technology, I am not want to use virtual method, because the class is arbitrary.
For example:
class A {
void setValue(int value);
};
How to define a template to call class A's setValue if it existing, else do nothing.
The template is something like:
template <typename T>
struct call_if_exist {
void invokeOrNot(T& a, int value){ // EXISTING: setValue
a.setValue(value);
}
}
template <typename T>
struct call_if_exist {
void invokeOrNot(T& a, int value){ // NOT EXISTING: do nothing
}
}
It's about invoking, not checking.
You can take advantage of SFINAE to make a class template that checks for the existence of a member function in a given class, and use the result as a boolean flag to specialize your template for the case when there is no function, and the case when the member function exists:
template<typename T , bool member_exists = has_set_value<T>::result>
struct call_if_exist;
template <typename T>
struct call_if_exist<T,true> {
void invokeOrNot(T& a, int value){ // EXISTING: setValue
a.setValue(value);
}
}
template <typename T>
struct call_if_exist<T,false> {
void invokeOrNot(T& a, int value){ // NOT EXISTING: do nothing
}
}
Edit: The has_set_value trait
template<typename T>
class has_set_value
{
typedef struct{ char c[1]; } yes;
typedef struct{ char c[2]; } no;
template<typename U> static yes test(&U::set_value);
template<typename U> static no test(...);
public:
static const bool result = sizeof( test<T>(NULL) ) == sizeof( yes );
};
This class is the typical example of the usage of SFINAE to check for the existence of a member (type or function) of a certain class.
First we define two typedefs, yes and no, which are used to differentiate overload resolutions through the sizeof operator.
The first overload of test() has a pointer to the member function as parameter, and the last is an overload which goal is to be called by everything thats not a pointer to the member. This is done through a variadic-function (Note the ellipsis), which can be used with any kind of parameter.
The point of the implementation is even if the second overload can hold any parameter, the first is an explicit case for pointers to our member function. So if the parameter could be a pointer to the function, the call is resolved to the first function, else its resolved to the second.
As I said before, we use the typedefs to differentiate the overload resolution through the sizeof operator: Note that the first overload returns yes and the later returns no. So if the size of the result type of the call to test() using a pointer (NULL) is equal to the size of yes, means that the overload is resolved to the first, and the class passed as parameter (T) has a member function called set_value.
Alexandrescu's Modern C++ Dessign includes an example of this kind of trait in chapter two to check if one type is implicitly convertible to other.