C++ template class, template member friend function matching rules - c++

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.

Related

Templated Using with Nested Template

The following code does not work because the inferred template parameter F is std::tuple, whereas I want it to be Foo - the former takes two template parameters and the latter takes one.
#include <tuple>
template <typename T>
using Foo = std::tuple<int, T>;
template <template <typename> class F>
void foo(F<std::string> bar) {}
void test() {
foo(Foo<std::string>());
}
Is there any way to make type inference work with the using statement rather than turning Foo into it's own class?
#include <tuple>
template <typename T>
class Foo {
std::tuple<int, T> bar;
};
template <template <typename> class F>
void foo(F<std::string> bar) {}
void test() {
foo(Foo<std::string>());
}
More Info
I am using C++17's std::variant along with using to alias types that are generic on a single type and I would prefer to declare these with using statements rather than creating wrapper classes for each one. Something like this:
// Assuming Plus, Minus, etc all exist
template <typename T>
using Operation = std::variant<Plus<T>, Minus<T>, Times<T>>;
Building a Haskell-Style Functor
The point of this exercise is to build a small functor library loosely based on Haskell's functor typeclass. I have defined the "typeclass" like this:
template <template <typename> class F>
class Functor {
public:
template <typename T, typename U>
static F<U> fmap(std::function<U(T)> f, F<T> functor);
};
But I also wanted to add some sugar so that you can create a general mapper that will map a function over any function type without pre-specifying the functor type:
template <typename T, typename U>
struct FMap {
FMap(std::function<U(T)> f) : f_(f) {}
template <template <typename> class F>
F<U> operator()(F<T> functor) {
return Functor<F>::fmap(f_, functor);
}
private:
std::function<U(T)> f_;
};
template <typename T, typename U>
FMap<T, U> fmap(std::function<U(T)> f) {
return FMap<T, U>(f);
}
This works well with a simple value-wrapper functor:
template <typename T>
class Value {
public:
Value(T value) : value_(value) {}
const T& value() const {
return value_;
}
private:
T value_;
};
template <>
template <typename T, typename U>
Value<U> Functor<Value>::fmap(std::function<U(T)> f, Value<T> value) {
return Value<U>(f(value.value()));
}
void test() {
std::function<std::string(int)> fn = [](int x) {
return std::to_string(x);
};
auto result = fmap(fn)(Value(42));
// result.value() == "42"
}
Now I am trying to get it to work with a more complicated type that uses std::tuple or std::variant like in the above example.
template <>
template <typename T, typename U>
Foo<U> Functor<Foo>::fmap(std::function<U(T)> f, Foo<T> value) {
return Foo<U>(std::get<0>(value), f(std::get<1>(value)));
}
void test() {
std::function<std::string(int)> fn = [](int x) {
return std::to_string(x);
};
// This is the desirable syntax but it doesn't build
// fmap(fn)(Foo<int>(42, 7));
// This builds but it's super ugly
fmap(fn).operator()<Foo>(Foo<int>(42, 7));
}
Based on the response by SkepticalEmpiricist below, I am thinking that type aliases may not be the way to go here and instead I will have to introduce small wrapper classes - unless there is an SFINAE approach that would get this working.
This library is mostly a curiosity and a means for me to explore some more advanced template concepts - thanks for the help!
So first attempt before we start digging for some SFINAE based trickery to try circumvent the unavoidable:
Alias templates are never deduced by template argument deduction
We could "deduce" the template arguments for the compiler ourselves like this:
#include <tuple>
template <typename T>
using Foo = std::tuple<int, T>;
template <template <typename ...> class F, typename T, typename ...Ts>
void foo(F<T, std::string, Ts...> bar) {}
void test() {
foo(Foo<std::string>());
}
So now we have it compiling for your foo(Foo<std::string>()); call with Foo being the alias template over std::tuple and, more importantly, foo() is still specialized only for Foo<std::string>.
However, to support usage simultaneously of foo() for both the std::tuple alias template and the wrapper class for example, we still don't have it compiling error-free. As in, if we now comment-out the tuple-flavor Foo and bring back in the wrapper class Foo then calling our rewritten foo() will not compile.
To address the issue, let's give it a try with SFINAE to the rescue and replace the last declaration of foo() with this code:
template <template <typename ...> class F, typename T, typename ...Ts,
typename std::enable_if_t<std::is_same<F<T, Ts...>,
std::tuple<T, Ts...>>::value >* = nullptr>
void foo(F<T, std::string, Ts...> bar) {}
template <template <typename> class F>
void foo(F<std::string> bar) {}
Now you can call foo() for instances of both wrapper class of tuples and alias template for tuples. You could implement in the same fashion for std::variant as well.
With:
template <typename T> using Foo = std::tuple<int, T>;
template <template <typename> class F> void foo(F<std::string> bar) {}
void test() { foo(Foo<std::string>()); }
Foo<std::string> is std::tuple<int, std::string>.
so test is
void test() { foo(std::tuple<int, std::string>()); }
How do you expect compiler deduce from tuple from which alias it come ?
we might have
template <typename T> using Bar = std::tuple<int, std::string>;
template <typename T> using Bar2 = std::tuple<some_trait<T>::type, some_trait<T>::type2>;
// ...
A possible workaround might be:
template <typename T, typename U>
Foo<U> fmap(std::function<U(T)> f, Foo<T> value)
{
return Foo<U>(std::get<0>(value), f(std::get<1>(value)));
}
With calling syntax:
fmap(fn, Foo<int>(42, 7));

SFINAE with variadic templates

I am somewhat new to template programming, so this might be a dumb question. I am trying to use variadic templates to check whether a class has a member (called member) or not. To do this, I have written the class
has_member.
#include <iostream>
using namespace std;
class ClassWithMember
{
public:
int member;
};
class ClassWithoutMember
{
};
template <typename T>
class has_member
{
template <typename... C>
class tester: public std::false_type
{
};
template <typename First>
class tester<First>: public std::true_type
{
void tester_fn(decltype(First::member));
};
public:
enum { value = tester<T>::value };
};
template<typename T1>
void my_function(const std::enable_if_t<has_member<T1>::value, T1> &obj)
{
cout<<"Function for classes with member"<<endl;
}
template<typename T1>
void my_function(const std::enable_if_t<!has_member<T1>::value, T1> &obj)
{
cout<<"Function for classes without member"<<endl;
}
int main()
{
ClassWithMember objWithMember;
ClassWithoutMember objWithoutMember;
my_function<ClassWithMember> (objWithMember);
my_function<ClassWithoutMember> (objWithoutMember);
}
I was expecting that by SFINAE, the substitution of the specialized template with classes without the member would fail silently and fall back to the general template. But I get the error:
trial.cpp: In instantiation of ‘class has_member<ClassWithoutMember>::tester<ClassWithoutMember>’:
trial.cpp:28:10: required from ‘class has_member<ClassWithoutMember>’
trial.cpp:38:41: required by substitution of ‘template<class T1> void my_function(std::enable_if_t<(! has_member<T1>::value), T1>&) [with T1 = ClassWithoutMember]’
trial.cpp:49:54: required from here
trial.cpp:24:14: error: ‘member’ is not a member of ‘ClassWithoutMember’
void tester_fn(decltype(First::member));
SFINAE only applies in the immediate context of the substitution. Substitution failure outside of that is an error. That's the issue you're running into:
has_member<ClassWithoutMember>::value // error
That's because the substitution failure doesn't occur in the declaration of has_member or tester, it occurs in the definition. That is too late. You need to push it much earlier. You can use void_t to push it into the specialization of has_member:
template <typename... T>
struct make_void { using type = void; };
template <typename... T>
using void_t = typename make_void<T...>::type;
template <typename T, typename = void>
struct has_member : std::false_type { };
template <typename T>
struct has_member<T, void_t<decltype(T::member)>> : std::true_type { };
Now, if there is no T::member, the substitution failure will occur in the immediate context of the substitution while trying to pick the correct specialization of has_member. That substitution failure is not an error, that particular specialization would just be discarded and we end up with false_type as desired.
As a side-note, the way you're using your enable_if_t prevents template deduction. You should prefer to write it this way:
template <typename T1,
std::enable_if_t<has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { ... }
template <typename T1,
std::enable_if_t<!has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { ... }
That would let you just write:
my_function(objWithMember);
my_function(objWithoutMember);

How to specialize a C++ templated-class function basing on a type-dependent type?

I have a C++ templated class
// Definition
template <typename T>
class MyCLass {
public:
typedef typename T::S MyS; // <-- This is a dependent type from the template one
MyS operator()(const MyS& x);
};
// Implementation
template <typename T>
MyCLass<T>::MyS MyClass<T>::operator()(const MyClass<T>::MyS& x) {...}
What I want is that overloaded operator operator() behaves differently when MyS is double.
I thought about specialization, but how to do in this case considering that the specialization should act on a type-dependent type? Thankyou
You could forward the work to some private overloaded function:
template <typename T>
class MyCLass {
public:
typedef typename T::S MyS;
MyS operator()(const MyS& x) { return operator_impl(x); }
private:
template<typename U>
U operator_impl(const U& x);
double operator_impl(double x);
};
You can solve this by introducing an extra default parameter:
template <typename T, typename Usual = typename T::S>
class MyClass { ... };
Then you can specialize using a double:
template <typename T>
class MyClass<T, double> { ... }

enable_if seems to work outside a class but not inside

Here is my somewhat odd code:
template <typename T&>
class A {
public:
void b(typename std::enable_if<!std::is_pointer<T>::value, T>;::type o) {}
void b(typename std::enable_if<std::is_pointer<T>::value, T>;::type o) {}
};
template <typename T>
void b(typename std::enable_if<!std::is_pointer<T>::value, T>::type o) {}
template <typename T>
void b(typename std::enable_if<std::is_pointer<T>::value, T>::type o) {}
If I ifdef out the method b and call b<int *>(pi) where pi is int *, everything compiles.
If I ifdef out the function b (outside class) and call A<int *> a; a.b(pi), I get the following error:
error: no type named 'type' in 'std::__1::enable_if<false, int *>'
Why the inconsistency and how can I fix the problem so that I can use the methods in A?
The problem is, that SFINAE only works during overload resolution and only if the function itself is a template. In your method case, the whole class is a template, meaning that there is no substitution of the template parameter (remember: SFINAE == "Substitution Failure Is Not An Error").
At the point of instantiation, the method signatures look like this (nevermind the call to them):
void A<int*>::b(std::enable_if<false, int*>::type o) // error
void A<int*>::b(std::enable_if<true, int*>::type o)
To fix this, make the methods templates too:
template<class T>
class A{
public:
template<class U>
void b(U o, typename std::enable_if<!std::is_pointer<U>::value>::type* = 0){}
// same for the other version
};
On a side note, letting the template argument get deduced is the better way to use SFINAE, so you should modify the free functions to look like this:
template<class T>
void b(T o, typename std::enable_if<!std::is_pointer<T>::value>::type* = 0){}
// same for the other version
In C++11, you can even use the template parameters for SFINAE:
template<class T, EnableIf<std::is_pointer<T>> = {}>
void b(T o);
Utilizing an alias from the blog entry linked from here:
namespace detail{ enum class enabler{}; }
template<class Cond, class T = detail::enabler>
using EnableIf = typename std::enable_if<C::value, T>::type;
For the explanation, see Xeo's answer.
For the work-around: just add a dummy template parameter to the method
#include <utility>
#include <type_traits>
template <typename T>
class A {
public:
template <typename U = T>
void b(typename std::enable_if<!std::is_pointer<U>::value, U>::type o);
template <typename U = T>
void b(typename std::enable_if<std::is_pointer<U>::value, U>::type o);
};
template <typename T>
template <typename U>
void A<T>::b(typename std::enable_if<!std::is_pointer<U>::value, U>::type o) {}
template <typename T>
template <typename U>
void A<T>::b(typename std::enable_if<std::is_pointer<U>::value, U>::type o) {}
int main() {
A<int> a;
a.b(0);
}
Live Demo Here.
You are not using SFINAE correctly because the compiler can't deduce the argument for enable_if<...>::type and probably that's why it fails.
Correct declarations of free-standing functions would be:
template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, void>::type b(T o);
template <typename T>
typename std::enable_if<std::is_pointer<T>::value, void>::type b(T o);
In this particular case plain function overloading can be used as well:
template <typename T>
void b(T);
template <typename T>
void b(T*);

Overloading template classes by template parameter number

Is it possible to have multiple versions of the same class which differ only in the number of template arguments they take?
For instance:
template<typename T>
class Blah {
public:
void operator()(T);
};
template<typename T, typename T2>
class Blah {
public:
void operator()(T, T2);
};
I'm trying to model functor type things which can take a variable number of arguments (up to the number of different templates that were written out).
The simplest answer would be to have just one template, with the maximum number you want to support and use void for a default type on all but the first type. Then you can use a partial specialization as needed:
template<typename T1, typename T2=void>
struct foo {
void operator()(T1, T2);
};
template <typename T1>
struct foo<T1, void> {
void operator()(T1);
};
int main() {
foo<int> test1;
foo<int,int> test2;
test1(0);
test2(1,1);
}
A template can have only one base definition. If you need a variable number of arguments and you don't want to use "null type" constructions as #awoodland suggests, and if you have a C++0x compiler, then you can use variadic templates:
template <typename ...Dummy> struct foo; // base case, never instantiated!
template <typename T> struct foo<T> { /*...*/ }; // partial spec. for one parameter
template <typename T, typename U> struct foo<T, U> { /*...*/ }; // ditto for two
This is untested code, I don't have a version of boost handy, but here goes anyway
#include "boost/tuple.h"
template <class T>
class Blah;
template <class T>
class Blah< boost::tuple<T> >
{
void operator()(T arg);
};
template <class T, class U>
class Blah< boost::tuple<T, U> >
{
void operator()(T arg1, U arg2);
};
etc. etc.