Template friend function of template class that introduces a new template parameter - c++

Thanks to Daniel Frey's answer to this post, I know how to declare a template friend function to a template class with the same template parameters. Unfortunately, the syntax for declaring a friend function with additional template parameters still escapes me. I would like to achieve something like this:
template <typename T>
class Obj;
template <typename T>
Obj<T> make_obj(T t);
template <typename T, typename RetVal>
RetVal ret_obj(T t);
template <typename T>
class Obj {
private:
T & t;
Obj (T & t) : t(t) { }
Obj() = delete;
friend Obj make_obj<T>(T t);
template <typename RetVal>
friend RetVal ret_obj<T, RetVal>(T t);
};
template <typename T>
Obj<T> make_obj(T t) {
return Obj<T>(t);
}
template <typename T, typename RetVal>
RetVal ret_obj(T t) {
return RetVal(make_obj(t).t);
}
I know that the same question has already been asked in this post, but the accepted answer there does not seem to be what I want: changing the parameter name to T2 makes the function a friend of all specializations of the object, while I want to keep T the same as in the class.

It is impossible to let friend declarations refer to partial specializations - either they refer to a specific specialization or to the primary template. Moreover, function templates cannot be partially specialized anyway.
What is not possible with function templates is often doable using class templates though:
template <typename T>
struct ret_obj_helper {
// Here goes the original definition of ret_obj - the important difference
// is the location of the template parameter T, which is the one
// fixed by the friend declaration below
template <typename RetVal>
RetVal ret_obj(T t) {return RetVal(make_obj(t).t);}
};
// I guess RetVal, having to be explicitly specified, better goes first (?)
template <typename RetVal, typename T>
RetVal ret_obj(T&& t)
{
// Overcomplicated for the sake of perfect forwarding
return ret_obj_helper<typename std::remove_reference<T>::type>{}.
template ret_obj<RetVal>(std::forward<T>(t));
}
template <typename T>
class Obj {
private:
T t;
Obj (T t) : t(t) { }
Obj() = delete;
friend Obj make_obj<T>(T t);
// Make all specializations of the member function template
// of ret_obj_helper<T> a friend, regardless of the return type
template <typename RetVal>
friend RetVal ret_obj_helper<T>::ret_obj(T t);
};
Demo.

Related

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

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.

Function template partial specialization - are there any workaround?

I have the following function
enum class NodeCachingOptions
{
AddPath,
DontAddPath
};
template <typename T, NodeCachingOptions>
T* CreateSObject(const MPath& path)
Idea was to specialize function for different NodeCachingOptions.
Turned out it is impossible to use partial function template specialization, thus I tried a workaround:
template <typename T, NodeCachingOptions>
T* CreateSObject(const MPath& ob)
{
CreateSObject_Impl<class T, NodeCachingOptions> temp
return temp.call(ob);
}
template <typename T, NodeCachingOptions>
struct CreateSObject_Impl
{
T* call(const MPath& ob);
};
template <typename T>
struct CreateSObject_Impl<typename T, NodeCachingOptions::AddPath>
{
T* call(const MDagPath& ob)
{…}
}
template <typename T>
struct CreateSObject_Impl<typename T, NodeCachingOptions::DontAddPath>
{…}
However I'm getting compile error: ::NodeCachingOptions': illegal type for non-type template parameter '__formal'
What am I doing wrong and is there a better way to solve this problem?
I took idea of struct impl from here: Partial template specialization of free functions - best practices
Your syntax is all wrong. Make it
template <typename T, NodeCachingOptions opt>
T* CreateSObject(const MPath& ob)
{
CreateSObject_Impl<T, opt> temp;
return temp.call(ob);
}
You pass the value of type NodeCachingOptions as the second template paramter of CreateSObject_Impl, not the type itself.
You may want to make call a static member of CreateSObject_Impl, and write return CreateSObject_Impl<T, opt>::call(ob);

Specialization template class with templated function

I have some helper template with templated function. I'm using it for other policy-based templated class to cast or not to cast some value to specific type:
// use this when needed additional value cast
template <typename T>
struct AdditionalValueStaticCaster
{
template <typename U>
static T cast(U u)
{
return static_cast<T>(u);
}
};
// use this specialization when no needed to cast value
template <>
struct AdditionalValueStaticCaster<void>
{
template <typename U>
static U cast(U u)
{
return u;
}
};
Now I want to split these classes to declaration and implementation (.h and .hh files)
So I write declaration like this:
template <typename T>
struct AdditionalValueStaticCaster
{
template <typename U>
static T cast(U u);
};
template <>
struct AdditionalValueStaticCaster<void>
{
template <typename U>
static U cast(U u);
};
And now I want to write implementation. This is ok:
template <typename T>
template <typename U>
T AdditionalValueStaticCaster<T>::cast(U u)
{
return static_cast<T>(u);
}
But this causes error error: too many template-parameter-lists
template<>
template <typename U>
U AdditionalValueStaticCaster<void>::cast(U u)
{
return u;
}
If I delete line template<> all compiles ok, but I still have a question: is it right solution or I missed something?
If I delete line template<> all compiles ok, but I still has question: is it right solution or I missed something?
That's correct, you just need to delete that line. AdditionalValueStaticCaster<void> is a concrete type and you're just providing the definition of a member function template on that type. Hence:
template <typename U>
U AdditionalValueStaticCaster<void>::cast(U u)
{
return u;
}
No different than the member function template on any other class type:
template <typename U>
U SomeClass::cast(U u)
{
return u;
}
I don't think that you can define a template with in a template.
put all the template parameters in the first template line. like this.
template <typename T, typename U>
struct AdditionalValueStaticCaster
{
static T cast(U u)
{
return static_cast<T>(u);
}
};
specialized to an actual object like this:
AdditionalValueStaticCaster< My_T_Type, My_U_Type> MyNewCaster;
and used like this
My_T_Type My_T_Type_var;
My_U_Type My_U_Type_var;
My_T_Type_var = MyNewCaster.cast(My_U_Type_var);
Sorry I don't have a compiler to check this on, but syntax should be close.

Error in template class

Hi I am trying to build empty functions for templates so that I can later fill in the details. Here is my code:
namespace my {
template <class T>
class Sptr {
private:
//some kind of pointer
//one to current obj
T obj;
size_t reference_count;
//one to original obj
public:
template <typename U> Sptr(U *);
Sptr(const Sptr &);
//template <typename U> Sptr(const Sptr<U> &);
~Sptr();
T* operator->() {return &obj;};
template <typename U> Sptr<T> &operator=(const Sptr<U> &);
//overload *,->,=,copy-constructor
// const-ness should be preserved.
// Test for null using safe-bool idiom
// Static casting, returns a smart pointer
};
template <typename U> Sptr<U>::Sptr(U* u) {
//do something
}
template <typename T> Sptr<T>::Sptr(const Sptr<T> &copyObj) {
//do copy constructor stuff
}
template <typename T> Sptr<T>::Sptr& operator=(const Sptr<T> &T) {
return *this;
}
}
But I get the following error when I compile it.
Sptr.hpp:30:24: error: prototype for ‘my::Sptr<T>::Sptr(U*)’ does not match any in class ‘my::Sptr<T>’
Sptr.hpp:17:3: error: candidates are: my::Sptr<T>::Sptr(const my::Sptr<T>&)
Sptr.hpp:16:25: error: template<class T> template<class U> my::Sptr::Sptr(U*)
Sptr.hpp:38:24: error: ‘my::Sptr<T>::Sptr’ names the constructor, not the type
How do I solve them?
template <typename U> Sptr<U>::Sptr(U* u) {
//do something
}
should be
template <typename T>
template <typename U>
Sptr<T>::Sptr(U* u) {
//do something
}
similarly for the other member function templates.
The way you define member functions of a class template is incorrect. Here is how you should define the constructor template:
template<typename T> // <== template parameter declaration for Sprt<T>
template<typename U> // <== template parameter declaration for constructor
Sptr<T>::Sptr(U* u) {
//do something
}
And here is how you should define the operator =:
template <typename T> // <== template parameter declaration for Sprt<T>
template<typename U> // <== template parameter declaration for operator
Sptr<T>& Sptr<T>::operator=(const Sptr<U> &t) {
return *this;
}
You define both the constructor and operator= as template functions. I'm not sure you actually want that. Shouldn't they just be taking T as arguments? Are you sure you don't want this for your constructor declaration:
Sptr(T*);
If you really do want them to be function templates, this is incorrect:
template <typename U> Sptr<U>::Sptr(U* u) {
//do something
}
When you have a function template inside a function class, you need to give both sets of template arguments:
template <typename T>
template <typename U>
Sptr<T>::Sptr(U* u) {
//do something
}

Specialize a template with a template

I have a (free) function template that looks like this
template <typename T>
T get();
I now want to specialize this function for a class, which itself is a template. But my compiler doesn't want to compile it, and I'm asking now if that is even possible and how I could achieve it. Just for the idea, the code could look as follows: (Doesn't compile)
template <>
template <typename T>
foo_type<T> get<foo_type<T>>()
What you're doing is called partial specialization of function template. But partial specialization of function template is not allowed. Overloading of function template is allowed, but in this case, it is not possible either, as the function has only return type, and overloading on return type is not allowed.
So the solution is this:
namespace details
{
template <typename T>
struct worker
{
static T get();
};
template <typename T> //partial specialization of class is allowed
struct worker<foo<T>>
{
static foo<T> get();
};
}
template <typename T>
T get()
{
return details::worker<T>::get();
}
You could also use overloads if you define them to take one argument so as to make overload valid:
namespace details
{
template <typename T>
static T get(T*);
template <typename T>
static foo<T> get(foo<T>*); //now the overload is valid
}
template <typename T>
T get()
{
return details::get<T>(static_cast<T*>(0));
}
Note that the argument static_cast<T*>(0) is used to help the compiler to select the correct overload. If T is other than foo<U>, then the first overload will be selected as the type of the argument passed to it will be T* as opposed to foo<U>*. If T is foo<U>, then the second overload will be selected by the compiler because it is more specialized, and can accept the argument passed to it which is foo<U>* in this case.
As Nawaz said, the standard just doesn't allow you to do that. You could however extract the implementation into the static method of a class and partially specialize that class.
template<class T>
struct get_impl{
static T get(){ ... }
};
template<class T>
struct get_impl<foo_type<T> >{
static foo_type<T> get(){ ... }
};
template<class T>
T get(){ return get_impl<T>::get(); }