Suppose we have the general function pointer:
template <class ArgT, class RetT, class F>
struct A {
F f;
public:
A(F f) : f(f) {}
RetT operator()(ArgT arg) { return f(arg); }
};
Why does this work?
template <class ArgT, class RetT, class F>
class B {
A<ArgT, RetT, F> test;
};
... and this not ?
class C {
template <class ArgT, class RetT, class F>
A<ArgT, RetT, F> test;
};
error C3857: 'C::test': multiple template parameter lists are not allowed
I need to define a class like in last example (class C), how can I do that?
Because variables can't have template. In fact just classes and functions can have template.
Edit: As Alan Stokes said, in C++14, variables also can have template.
Related
when attempting to get functions' signatures when they are input into templates its fairly easy, just do the following:
template <class OutType, class... ArgTypes>
void foo(OutType (*func)(ArgTypes...));
it is only marginally more complicated to get a non-static member function:
template <class OutType, class MemberOf, class... ArgTypes>
void foo(OutType (MemberOf::*func)(ArgTypes...));
// or
template <class OutType, class MemberOf, class... ArgTypes>
void foo(OutType (MemberOf::*func)(ArgTypes...) const);
but how exactly do you combine the two function declarations above into one when it doesn't matter whether or not the input method is const?
Unfortunately, the presence or absence of const on a non-static member function is not a feature that can be deduced separately from the function type it appertains to. Therefore, if you want to write a single foo template declaration that is limited to accepting pointers to members (but accepts both const and non-const member functions) then it would have to be:
template <class MemberOf, class F>
void foo(F MemberOf::*func);
For example:
#include <type_traits>
template <class MemberOf, class F>
void foo(F MemberOf::*func) {
static_assert(std::is_same<F, void(int) const>::value);
}
struct S {
void bar(int) const {}
};
int main() {
foo(&S::bar);
}
You cannot have F's argument types deduced at that point. You would have to dispatch to a helper function. (But we cannot deduce all the types at once while also writing a single declaration that accepts both const and non-const. If that's the only thing you'll accept, then sorry, it's not possible.) We can do this like so:
template <class T>
struct remove_mf_const;
template <class R, class... Args>
struct remove_mf_const<R(Args...)> {
using type = R(Args...);
};
template <class R, class... Args>
struct remove_mf_const<R(Args...) const> {
using type = R(Args...);
};
template <bool is_const, class F, class OutType, class MemberOf, class... ArgTypes>
void foo_helper(F func, OutType (MemberOf::*)(ArgTypes...)) {
// now you have all the types you need
}
template <class MemberOf, class F>
void foo(F MemberOf::*func) {
static_assert(std::is_function<F>::value, "func must be a pointer to member function");
using NonConstF = typename remove_mf_const<F>::type;
constexpr bool is_const = !std::is_same<F, NonConstF>::value;
foo_helper<is_const>(func, (NonConstF MemberOf::*)nullptr);
}
Coliru link
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.
I am writing Monitor class for synchronization problem and I would like to implement an 'Entry' class that will wrap a std::function.
I implemented it a bit, used function traits, but right now I am only able to construct Entry objects using prepared std::function object. Attempts to write a constructor that has an plain function as a parameter failed with compiler messages about template argument deduction/substitution and <anonymous> parameter.
The program is working but I am just curious how to implement given constructor, this is my code:
template <class F>
struct FunctionType;
template <class R, class Object, class... Args>
struct FunctionType<R (Object::*)(Args...)> {
typedef R return_type;
};
template <class R, class Object, class... Args>
struct FunctionType<R (Object::*)(Args...) const> {
typedef R return_type;
};
template <class F> class Entry {
std::function<F> internalFunction;
...
public:
template <F> Entry(const F& function){
// It doesn't work.
}
template <F> Entry(const std::function<F> function) :
internalFunction(function) {
}
template<F, class... Arguments>
typename FunctionType<F>::return_type operator()(Arguments... arguments){
return internalFunction(arguments...);
}
};
A couple of things:
template<F>
doesn't make any sense at all. You get the type of F from the template parameter on the class, use that and remove this altogether.
Next, it's probably easier for you to use a trailing return type on your operator() function:
template<class... Arguments>
auto operator()(Arguments... arguments) -> decltype(internalFunction(arguments...))
{
return internalFunction(arguments...);
}
(If you have C++14 you can just use auto).
Live Demo
Here's your fixed class
template <class F> class Entry {
std::function<F> internalFunction;
public:
Entry(const F& function){
// It doesn't work.
}
Entry(const std::function<F> function) :
internalFunction(function) {
}
template<class... Arguments>
auto operator()(Arguments... arguments) -> decltype(internalFunction(arguments...)){
return internalFunction(arguments...);
}
};
I have a class, Delegate, declared like this:
template<typename T> class Delegate;
template<typename R, typename... Args>
class Delegate<R(Args...)>
{ /*...*/ };
It can be instantiated for a function returning a ReturnType and taking no arguments as a Delegate<ReturnType()>. I've run into an issue that requires me to specialize the class' () operator for this case, but haven't been able to figure out how to coerce the compiler doing so without a compiler error.
I have the following function:
template <typename R, typename... Args>
R Delegate<R(Args...)>::operator()(Args... args)
{ /*...*/ }
Adding the following specialization, I get an an error saying invalid use of incomplete type 'class Delegate<R()>':
template <typename R>
R Delegate<R()>::operator()()
{ /*...*/ }
but I can't simply replace Args... with void either, as far as I've been able to tell... What is the proper procedure here, and (if this question applies and you are feeling extra helpful) why?
Your attempt with using R Delegate<R()>::operator()() to specialize even more the member function of a partial specialization of a class template fails due to ยง14.5.5.3 [temp.class.spec.mfunc]:
1 The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization.
In other words:
template <typename R>
R Delegate<R()>::operator()() { /**/ }
is actually a specialization of operator() of your primary template:
template <typename T>
class Delegate;
and since it's an incomplete type, you end up with the error. The possible workarounds are:
Option #1
Specialize the entire class and reimplement all the members of that class:
template <typename T>
class Delegate;
template <typename R, typename... Args> // partial specialization for non-empty Args
class Delegate<R(Args...)>
{
R operator()(Args...) { return {}; }
};
template <typename R> // partial specialization for empty Args
class Delegate<R()>
{
R operator()() { return {}; }
};
DEMO 1
Option #2
Use a one more delegate class that is specialized:
#include <utility>
template <typename T>
struct Impl;
template <typename R, typename... Args>
struct Impl<R(Args...)>
{
static R call(Args&&...) { return {}; }
};
template <typename R>
struct Impl<R()>
{
static R call() { return {}; }
};
template <typename T>
class Delegate;
template <typename R, typename... Args>
class Delegate<R(Args...)>
{
R operator()(Args... args)
{
return Impl<R(Args...)>::call(std::forward<Args>(args)...);
}
};
DEMO 2
Option #3
Use some ugly SFINAE:
#include <type_traits>
template <typename T>
class Delegate;
template <typename R, typename... Args>
class Delegate<R(Args...)>
{
template <typename T = R>
typename std::enable_if<sizeof...(Args) != 0 && std::is_same<T,R>{}, R>::type
operator()(Args...) { return {}; }
template <typename T = R>
typename std::enable_if<sizeof...(Args) == 0 && std::is_same<T,R>{}, R>::type
operator()() { return {}; }
};
DEMO 3
Option #4
Inherit from a specialized class template, possibly utilizing the CRTP idiom:
template <typename T>
class Delegate;
template <typename T>
struct Base;
template <typename R, typename... Args>
struct Base<Delegate<R(Args...)>>
{
R operator()(Args...)
{
Delegate<R(Args...)>* that = static_cast<Delegate<R(Args...)>*>(this);
return {};
}
};
template <typename R>
struct Base<Delegate<R()>>
{
R operator()()
{
Delegate<R()>* that = static_cast<Delegate<R()>*>(this);
return {};
}
};
template <typename R, typename... Args>
class Delegate<R(Args...)> : public Base<Delegate<R(Args...)>>
{
friend struct Base<Delegate<R(Args...)>>;
};
DEMO 4
How to declare a variadic template function as a friend?
For example as follows:
template<class T>
class A
{
friend ??? MakeA ??? ; // What should be placed here ???
A(T)
{}
};
template<class T, class... Args>
A<T> MakeA(Args&&... args)
{
T t(std::forward<Args>(args));
return A(t);
}
It's quite straightforward. It's simply a template declaration with the added friend specifier:
template<class T>
class A
{
template<class T1, class... Args>
friend A<T1> MakeA(Args&&... args);
A(T) { }
};