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> ©Obj) {
//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
}
Related
I have a template class alpha_x give as,
template <typename T,typename U>
struct alpha_x {
const T & alpha;
const Scalar<U> & x;
alpha_x(const T & a_, const Scalar<U> & x_) : alpha(a_), x(x_) {};
};
I have another class with an overload for operator =
template <typename T>
class Scalar{
...
template <typename U,typename V>
const Scalar<T> & operator = (alpha_x<U,V> c);
...
}
When we try to define this function,
template <typename T,typename U,typename V>
const Scalar<T> & Scalar<T>::operator = (alpha_x<U,V> c){
//do something...
}
Now this gives an error "Too many template parameters in template redeclaration". How do I sort this out?
T template parameter is a class Scalar's template parameter. Thus it needs to be specified in a separate template parameter list.
Following would work:
template <typename T>
template <typename U, typename V>
const Scalar<T> & Scalar<T>::operator = (alpha_x<U,V> c){
// do something...
}
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 have a template class that declares a friend function which itself has template parameters. The code looks like this:
template <class T>
class C;
template <class T, class U>
void func(C<T>& t);
template <class T>
class C
{
template <class U>
friend void func<T, U>(C<T>& t);
private:
template <class U>
void f()
{
}
};
template <class T, class U>
void func(C<T>& t)
{
t.f<U>();
}
But when I try to call func, I get a compilation error at the friend line:
'func': no matching overloaded function found
How can I make func<T, U> friend with C<T>?
The key issue is that the friend you declared, is not the same as the previous declaration you provided. The first expects two template parameters, but the second (friend) you defined to accept only one. Once that is resolved, everything works:
template <class T>
class C;
template <class U, class T>
void func(C<T>& t);
template <class T>
class C
{
template <class U, class TT>
friend void func(C<TT>& t);
private:
template <class U>
void f()
{
}
};
template <class U, class T>
void func(C<T>& t)
{
t.template f<U>();
}
int main() {
C<int> c;
func<bool>(c);
}
Watch it live.
Note I switched U and T up, because I assumed you may want T deduced and U explicitly specified.
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.
Here is my class declaration:
template <class T>
class Sptr {
template<typename U> friend class Sptr;
template <typename T1, typename T2>
friend bool operator==(const Sptr<T1> &a, const Sptr<T2> &b);
template <typename U>
friend Sptr<T> static_pointer_cast(const Sptr<U> &sp);
private:
RC* ref; //reference counter
T* obj;//pointer to current obj
std::function<void()> destroyData;
bool ok_;
public:
Sptr();
~Sptr();
template <typename U>
Sptr(U *);
Sptr(const Sptr &);
template <typename U>
Sptr(const Sptr<U> &);
template <typename U>
Sptr<T> &operator=(const Sptr<U> &);
Sptr<T> &operator=(const Sptr<T> &);
void reset();
T* operator->() const
{return obj;};
T& operator*() const
{return *obj;};
T* get() const
{return obj;};
explicit operator bool() const {
return ok_;
}
};
Below is the code thats complaining of access problem
template <typename T, typename U>
Sptr<T> static_pointer_cast(const Sptr<U> &sp) {
//do something
Sptr<U> answer;
answer.obj = sp.obj;
answer.ref = sp.ref;
answer.destroyData = sp.destroyData;
answer.ok_ = sp.ok_;
return answer;
}
when I compile with the following code:
Sptr<Derived> sp(new Derived);
Sptr<Base1> sp2(sp);
// Sptr<Derived> sp3(sp2); // Should give a syntax error.
Sptr<Derived> sp3(static_pointer_cast<Derived>(sp2));
// Sptr<Derived> sp4(dynamic_pointer_cast<Derived>(sp2)); // Should give syntax error about polymorphism.
I have already made it a friend function. Why is it not able to access the variables and how to correct it?
This is a bit tricky. Your code compiles if you replace
template <typename U>
friend Sptr<T> static_pointer_cast(const Sptr<U> &sp);
with
template <typename T1, typename T2>
friend Sptr<T1> static_pointer_cast(const Sptr<T2> &sp);
The reason is the following (I am not 100% sure, so please someone approve / dis-approve):
When Sptr<T> is instantiated, e.g. with T = Derived, the resulting class definition (Sptr<Derived>) defines a friend function having the following signature:
template <typename U>
friend Sptr<Derived> static_pointer_cast(const Sptr<U> &sp);
So this is a function which only has one template parameter. But the function you defined has two template parameters.
Your call to this templated function is a specialization which looks like this:
Sptr<Derived> static_pointer_cast(const Sptr<Base1> &sp) {
//do something
Sptr<Derived> answer;
answer.obj = sp.obj;
answer.ref = sp.ref;
answer.destroyData = sp.destroyData;
answer.ok_ = sp.ok_;
return answer;
}
So it tries to access both Base1 and Derived, but it's only a friend of Derived, not of Base1. This last sentence is the important thing, and changing it to a friend function with two template parameters solves this issue.
You said friend sptr<t>, which means it can only access the private members of sptrs to the same type. since sp2 is not a sptr( t is derived) it is not a friend. Try :
template< class u, class v> friend sptr<u> static_pointer_cast(const sptr<v> &sp);