Template by method pointer in clang vs gcc and msvc - c++

I have this function:
template <typename T, void (T::*pf)()>
void call(T& t)
{
(t.*pf)();
}
If I have class foo with a method with the appropriate signature (say bar) I can call it like this call<foo, &foo::bar>(); and it's fine. However if bar is const gcc and msvc are happy to compile it when called like this call<const foo, &foo::bar>(). Clang complains that the second template parameter is invalid. When I put const in the template arguments (void (T::*pf)() const) all tree compile it.
Now, this is not a huge issue, but my code becomes much much cleaner if I don't have to write this wretched const in the template arguments.
So the question basically is: What does the standard say about this? Is this a clang bug or are gcc and msvc just letting it slide because they're cool like that?
PS Here's a link to a complete repro program: http://codepad.org/wDBdGvSN

The const-ness of a method is part of the 'signature' of it. So, the proper way to define and use a pointer to member is:
R (Obj::*)(Args) // for non-const member
R (Obj::*)(Args) const // for const member
Note that a const member can be called on a non-const object, which is not the case with R (const Obj::*)(Args).
A way to solve this is to abstract such function pointers, by defining 'call wrappers':
template<typename O, void (O::* f)()>
struct NonConstFunc
{
static void call(O* o)
{
(o->*f)();
}
};
template<typename O, void (O::* f)() const>
struct ConstFunc
{
static void call(O* o)
{
(o->*f)();
}
};
Then, you can use it the following way (here the abstraction takes place):
template<typename Obj, typename Function>
void call(Obj* o)
{
Function::call(o);
}
There is a live example here.
This is just the main idea. You can extend it with automatic detection of whether the method is const or not, without changing the user code.

Related

concept to check existence of function in class (problem in GCC?)

I would like to detect if a function (operator() in my case) is present in a class, regardless of its signature or whether it would be possible to get a pointer to it (may be impossible without additional info because it is templated or overloaded). The following code using a concept compiles on MSVC and clang, but not GCC (see godbolt link below for error messages). Is this supposed to work and is GCC not conformant, or is this not supposed to work and are MSVC and clang too lenient? It is interesting to note GCC fails not only for the overloaded and templated operator()s, but also for the simple functor.
Note also that while the example code uses variations on unary functions taking an int, I'd like the concept to work regardless of function signature (and its does for MSVC and clang).
Try here for GCC, clang and MSVC.
Context is making this work, it does now on MSVC and clang, but not GCC.
template <typename C>
concept HasCallOperator = requires(C t)
{
t.operator();
};
struct functor
{
int operator()(int in_)
{ return 1; }
};
struct functorOverloaded
{
int operator()(const int& in_)
{ return 1; }
int operator()(int&& in_)
{ return 1; }
};
struct functorTemplated
{
template <typename... T>
int operator()(const T&... in_)
{ return 1; }
};
template<HasCallOperator T>
struct B {};
int main()
{
B<functor> a;
B<functorOverloaded> b;
B<functorTemplated> c;
}
First, the way to check a concept is just to static_assert (not to try to instantiate a constrained class template).
static_assert(HasCallOperator<functor>);
static_assert(HasCallOperator<functorOverloaded>);
static_assert(HasCallOperator<functorTemplated>);
Second, you can't write t.operator() for the same reason that you can't write f.fun for any other non-static member function: if you do class member access, it must end with invocation. So this is simply a clang/msvc bug that it allows any of this.
And then &C::operator() will not work if the call operator is overloaded or a function template (or both).
Which really calls into question the whole point of this, since without reflection we're highly limited in the kinds of answers we can give to these questions. You can really only address the simple case of non-overloaded, non-template call operator.
Nevertheless, there is an approach that works here. The trick is the same problem we have in our present case: &C::operator() doesn't work if operator() is overloaded.
So what we do instead is construct a case where &C::operator() would be overloaded if there were one, and invert the check. That is:
#include <type_traits>
struct Fake { void operator()(); };
template <typename T> struct Tester : T, Fake { };
template <typename C>
concept HasCallOperator = std::is_class_v<C> and not requires(Tester<C> t)
{
&Tester<C>::operator();
};
HasCallOperator<C> doesn't check C, it checks a type that inherits from both C and a type that has a non-overloaded non-template call operator. If &Tester<C>::operator() is a valid expression, that means it refer to &Fake::operator(), which means that C did not have one. If C had a call operator (whether it's overloaded or a template or both or neither), then &Tester<C>::operator() would be ambiguous.
The is_class_v check is there to ensure that stuff like HasCallOperator<int> is false rather than ill-formed.
Note that this won't work on final classes.

boost function to any functor with template operator ()

I want to store boost::function<void(void*)> in order to point to an arbitrary functor class object. I tried the following code, but it does not compile :
struct MyFunctor
{
template<class T>
void operator()(T* a)
{
T& ref = *a;
}
};
struct MyFunctor2
{
template<class T>
void operator()(T* a)
{
T& ref = *a;
}
};
boost::function<void(void*)> anyFunctorPtr;
anyFunctorPtr= MyFunctor();
double a = 5;
anyFunctorPtr(&a);
The compiler error is error C2182: 'ref' : illegal use of type 'void'
boost::function, just like std::function requires a specific functor signature (in your case void(void*)), which is the signature it will try to call your functor with. That's why T is deduced as void and the compiler refuses to give you a void&, rightfully so.
Your example is fundamentally add odds with itself, because if you want to have type erasure, you cannot have templates, as the compiler cannot know which templates to instantiate otherwise. Assume for a moment that boost::function<magic> could do what you want.
If you give the compiler code like this:
void foo(boost::function<magic> func)
{
double a = 5;
func(&a);
}
How would the compiler know whether to generate a T = double instantiation for MyFunctor or MyFunctor2? It simply cannot know, and thus it cannot generate the right code. There is no limit on the amount of templated functor classes you can have and the number of types you can attempt to call operator() with, so instantiating them automatically ahead of time is also out of the question.

Template parameter deduction for parameters not used in function call

So, I'm editing my wrapper around an OpenGL Shader Program. I'm trying to modify it to use templates for the functions to set uniforms, as they are all almost the same.
My desired end result is for the call:
aProgram.set_Fglm("uformName", glm::vec3(0, 1, 2));
To call the template function:
template<class T, void (*F)(GLint, GLsizei, const GLfloat*)>
void Shader::set_Fglm(const string& _name, const T& _value) {
// do stuff using F()
}
with the template parameters <glm::vec3, gl::Uniform2fv>. Currently, I have in my cpp file the code:
template void Shader::set_Fglm<glm::vec3, gl::Uniform3fv>
(const string& _name, const glm::vec3& _value);
However, what currently happens is that I get a compile time error, saying that the Template parameter F can not be deduced. So, what I think I need is a way to say that, when we receive a parameter of type glm::vec3, we always want to use the same gl function.
If possible, I also wouldn't mind if, for example, I needed to call something like aProgram.set_F3glm. But if that's the case, how would I still have the implementation itself written only once. What I had before just stored an enum with each uniform that would then be checked to see what function to call, and the set function would just always take a c pointer.
Sorry if this is worded pretty terribly, but I'm not really sure what I'm doing.
You may write a traits for that, something like:
template <typename T> struct DefaultF;
// Specialization
template <>
struct DefaultF<glm::vec3>
{
static constexpr void (*Func)(GLint, GLsizei, const GLfloat*) = &gl::Uniform2fv;
};
template<class T, void (*F)(GLint, GLsizei, const GLfloat*) = DefaultF<T>::Func>
void Shader::set_Fglm(const string& _name, const T& _value) {
// do stuff using F()
}
Example
Note that you may remove template parameter F and use directly DefaultF<T>::Func in your function.

Explicit specialization using variadic parameters within variadic templated class [MSVS '12: Nov. '12 CTP: error C3522]

I'm trying to expand a class's variadic template type list within a child method as such:
template<typename... P>
struct Foo
{
template<P...> // error C3522: 'P' : parameter
// pack cannot be expanded in this context
static void Bar(P... a){}
};
What is wrong with this code, or is it just a MSVS '12: Nov. '12 CTP bug?
(Yes, I know the explicit template specialization in this example is redundant.)
The above is the simplest case that I get to reproduce the error. The full code is:
template<typename FuncSignature>
class Callback;
template<typename R, typename... P>
class Callback<R (P...)>
{
public:
Callback() : func(0), obj(0) {}
Callback& operator=(const Callback& rhs)
{ obj = rhs.obj; func = rhs.func; return *this; }
private:
typedef R (*FuncType)(const void*, P...);
Callback(FuncType f, const void* o) : func(f), obj(o) {}
private:
FuncType func;
const void* obj;
template<typename FR, typename... FP>
friend class FreeCallbackFactory;
};
template<typename R, typename... P>
class FreeCallbackFactory
{
private:
template<R (*Func)(P...)>
static R Wrapper(const void*, P... a)
{
return (*Func)(a...);
}
public:
template<R (*Func)(P...)>
inline static Callback<R (P...)> Bind()
{
return Callback<R (P...)>
(&FreeCallbackFactory::Wrapper<Func>, 0);
}
};
template<typename R, typename... P>
inline FreeCallbackFactory<R, P...>
GetCallbackFactory(R (*)(P...))
{
return FreeCallbackFactory<R, P...>();
}
void Test(){}
int main(int argc, char** argv){
Callback<void ()> cb = GetCallbackFactory(&Test).Bind<&Test>()
}
It compiles fine in g++ so I'm assuming just a compiler bug, and continued findings still only point to this, are there any possible workarounds for this other than explicitly expanding them out one by one?
Edit: This has been reported to the compiler team as a bug and a patch will be in the next release of the compiler. [Link]
The code looks correct put I doubt that it does what you intended it to do: The declaration
template <P...>
static void Bar(P... a);
declares a function taking P... values as template argument and as function argument. That is, the elements of P need to be of a type allowing non-type parameters (e.g., integers, pointers, or references) and you'd need to provide their respective values as template parameters when calling the function. The call to a function like this would look something like this (although it seems neither gcc nor clang require the template parameters to be passed):
Foo<int, int>::Bar<1, 2>(3, 4);
That said, based on the error messages generated by both gcc and clang it seems that they won't let you create a specialization of member function templates but I haven't verified this in the standard. I think, you should probably just leave out the template declaration and use
static void Bar(P... a);
To me the code does not look correct. The pack expansion P... expands to a set of types. Depending on what you aim to achieve the correct thing to do would be to remove the template<P...> part, in which case each class template instance has one Bar() method with the same parameters as the class. The other would be that this is an unrelated parameter pack in which case an unbounded set of methods is generated, in that case you must declare the method something like:
template<typename... U> static void Bar(U...);
reusing the name P would not be very useful, I guess.

Conditional Compile using Boost type-traits

I have a template that I would like to conditionally compile depending on the type of the argument. I only care about differentiating between "Plain Old Data" (POD), i.e., integers, etc or classes/structs. I'm using c++ VS2008 on Windows.
template<T>
class foo
{
void bar(T do_something){
#if IS_POD<T>
do something for simple types
#else
do something for classes/structs
#endif
}}
I've been looking at the boost library's and I can see that they appear to have what I want. However, I do not understand what the correct syntax for the #if statement would be.
Any help would be appreciated.
Edit ---
After reading the responses, I see I overlooked something in my definition of the question. Class foo is a templated class that only needs to instance the version of bar that is correct for class type T. I was looking for a solution that can be resolved a compile time. Hope this clears up my problem.
You can do it without enable_if, because all you need is to dispatch depending on type traits. enable_if is used to add/remove template instantiations to/from overload resolution. You may want to use call traits to choose the best method to pass objects to your function. As a rule, objects should be passed by reference, whereas POD is passed by value. call_traits let's you choose between const and non-const references. The code below uses const reference.
#include <boost/type_traits.hpp>
#include <boost/call_traits.hpp>
template <typename T>
class foo {
public:
void bar(typename boost::call_traits<T>::param_type obj) {
do_something(obj, boost::is_pod<T>());
}
private:
void do_something(T obj, const boost::true_type&)
{
// do something for POD
}
void do_something(const T& obj, const boost::false_type&)
{
// do something for classes
}
};
You can't solve this with the preprocessor, since it doesn't know about C++. (It's a dumb text replacement tool.) Use templates to do this.
Assuming IsPod<T>::result returns something alike Boolean<true>/Boolean<false>:
template<T>
class foo
{
void do_something(T obj, Boolean<true> /*is_pod*/)
{
// do something for simple types
}
void do_something(T obj, Boolean<false> /*is_pod*/)
{
// do something for classes/structs
}
void bar(T obj)
{
do_something(obj, IsPod<T>::result());
}
}
Using preprocessor here is not possible. Have a look at Boost Enable If library instead.
Specifically, in your case it would look like (not tested):
void bar (typename enable_if <is_pod <T>, T>::type do_something)
{
// if is POD
}
void bar (typename disable_if <is_pod <T>, T>::type do_something)
{
// if not
}