template friend function overloading - c++

I was reading the std::enable_shared_from_this(g++ version) source code in the past two days. There is two questions confuse me.
Let me show brief source code first.
template<typename _Tp>
class enable_shared_from_this {
...
private:
template<typename _Tp1>
friend void
__enable_shared_from_this_helper(const __shared_count<>& __pn,
const enable_shared_from_this* __pe,
const _Tp1* __px) noexcept {
}
};
template<typename _Tp1, typename _Tp2>
void
__enable_shared_from_this_helper(const __shared_count<>&,
const enable_shared_from_this<_Tp1>*,
const _Tp2*) noexcept;
Questions:
1. note the line const enable_shared_from_this* __pe, there is no tag '<>' after enable_shared_from_this, does this imply enable_shared_from_this<__Tp1> here?
2. There is two overload function template __enable_shared_from_this_helper here, my test shows that the version defined in class enable_shared_from_this will always be called, why?
Thank you guys, would appreciate any effort.

For 1.: No, it means that the <_Tp> is implicit here, not the <_Tp1> from the additional template parameter. When you leave out the template parameters of the class name within the definition of a class (or the body of a member-method's definition), and a type is expected, the parameters from the class itself are implied.
For 2.: This is the same as the first one just with _Tp1 instead of _Tp and with _Tp2 instead of _Tp1.

Related

Can someone help me explain what the second line of the code means? This is in C++

My professor gave us this piece of code to study to better understand how class templates work in C++ but I'm confused on what the second line means. I put two asterisks (**) next to the statement I'd like more clarification on.
template<typename T>
Pair<T>::Pair(const T& firstVal, const T& secondVal) //**
{
first = firstVal;
second = secondVal;
}
This is the Pair class template :
template<typename T>
class Pair
{
public:
Pair();
Pair(const T& firstVal, const T& secondVal);
void setFirst(const T& newVal);
void setSecond(const T& newVal);
T getFirst() const;
T getSecond() const;
~Pair(){}
private:
T first, second;
};
What I'm confused about is why she's treating the constructor as a function and defining it as the class has no member functions with the name "Pair" apart from the constructor? I'm sure I'm misunderstanding something about constructors and functions and if someone could help I'd greatly appreciate it, thank you!
The mentioned snippet is an out-of-class definition for a constructor of a class template. In particular, to define a member function(which a constructor also is) of a class template, we have to specify that it is part of a template and so we have to use the full type qualification of the class template.
For instance, say you want to have an out-of-class definition for the member function setFirst, then you would define it as follows:
template<typename T> //parameter clause goes here
void Pair<T>::setFirst(const T& newVal) //full type qualification goes here
{
}
Similarly, if we want to have an out-of-class definition for the constructor then we will do it as follows:
template<typename T>//parameter clause is here
Pair<T>::Pair(const T& firstVal, const T& secondVal)//full type qualification is here
: first(firstVal), second(secondVal)
{
}
Note that a constructor is a special member function.
Well, Pair() and Pair(const T& firstVal, const T& secondVal) are both functions. Constructors are functions that are called when the object is initialised, and you can define and then implement the constructors later, just like any other normal member function.
A non-templated class's constructor implementation would look like this:
myClass::myClass(/* my args ... */) {
// do stuff ...
}
And, if myClass is a templated class, you would have to have type T defined somewhere, and that would be done like so:
template <typename T>
myClass<T>::myClass(/* my args ... */) {
// do stuff ...
}
This lets you also define specific specialisations, say if you want your class's constructor to have specific functionality for when T = int. You would define it using the template!
template<>
myClass<int>::myClass(/* my args ... */) {
// do special integer stuff!
}

C++ concepts: Some signatures function conversion

Unfortunately, the only tutorial that I have found about concepts was the concept lite tutorial (and it was really basic). And even with the technical specification, there is some signatures function that I don't know how translate into concepts (maybe just because my English is bad and I can't read the technical specification really well).
So there is a list of signatures function I still don't know how to "translate":
CFoo --> class CFoo {};
void Foo1() const;
CFoo& Foo2();
void Foo3(CFoo&);
{static, friend, ... } void Foo4();
template < typename ... Args >
void Foo5(Args && ... args);
I want to have some kind of interface for a class with these functions.
Don't even know if it's possible at this point. Foo2 and Foo3 seems to be the same problem.
Honestly I really want to know Foo2 and Foo5.
I tried somethings, for the Foo2 but I don't have any idea about Foo5:
class Handle {};
template < typename Object >
concept bool C_Object =
requires(Handle handle) {
{get(handle)} -> Object&
};
template < C_Object Object >
class Foo {
Object obj;
};
int main() {
Foo<int> test;
return 0;
}
I know this won't compile because Foo don't have a get menber, but these are not the right errors:
Test1.cpp:6:16: error: there are no arguments to ‘get’ that depend on a template parameter, so a declaration of ‘get’ must be available [-fpermissive]
{get(handle)} -> Object&
^
Test1.cpp:6:16: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
Test1.cpp: In function ‘int main()’:
Test1.cpp:18:10: error: template constraint failure
Foo<int> test;
^
Test1.cpp:18:10: note: constraints not satisfied
Test1.cpp:4:14: note: within ‘template<class Object> concept const bool C_Object<Object> [with Object = int]’
concept bool C_Object =
^~~~~~~~
Test1.cpp:4:14: note: with ‘Handle handle’
Test1.cpp:4:14: note: the required expression ‘get(handle)’ would be ill-formed
If someone can point me out some resources or, why not, a solution. It will be great.
Have a great day
I know this won't compile because Foo don't have a get menber […]
Concepts deal with normal expressions. In particular, the scope of requires expressions is normal scope, not class scope. This may be more apparent with this concept:
template<typename Lhs, typename Rhs>
concept bool Addable = requires(Lhs lhs, Rhs rhs) {
lhs + rhs;
};
Addable<int, long> is fulfilled because given int lhs; long rhs; then lhs + rhs is a valid expression. We're using the built-in addition operator on two (pretend) variables we explicitly introduced in the parameter list, not calling a member operator+ on an implicit *this.
Concepts are about interfaces in the wider sense (as in 'API'), not in a narrower OOP sense. You can think of Addable as a relation on pairs of types. That Addable<int, long> holds doesn't mean int on its own has a special relationship with Addable. It is true that Addable can be used as e.g.
template<Addable<long> Var>
struct client {
Var var;
};
and then client<int> comes with an Addable<int, long> constraint, but this shortcut is syntactical in nature. It's a helpful way of cutting down boilerplate, namely sparing us from writing template<typename Var> requires Addable<Var, long>.
With that in mind, here are some expressions that may come close to checking the member signatures you mentioned, plus the Handle scenario:
template<typename Obj>
concept bool Object = requires(Obj obj, Obj const cobj, Handle handle) {
cobj.Foo1();
{ obj.Foo2() } -> Obj&;
obj.Foo3(obj);
// static
Obj::Foo4();
// non-member, possibly friend
Foo4(obj);
{ obj.get(handle) } -> Obj&;
};
(I elided the Foo5 scenario because it's worth its own question, here is a lead.)

C++, partial specialization of 2-argument class template: unable to match function definition to an existing declaration

I'm currently implementing a dataset helper class template storing floating point values (Scalar) in a dynamically sized Eigen::Matrix constructed from a vector of different values types (Element) additionally storing a reference to this input vector. Now i want to partially specialize the constructor in the vector value type remaining a template in the scalar type to be explicitly instantiated.
Unfortunately i'm getting "unable to match function definition to an existing declaration" on VS 2010. The code is as simple as:
template <class Scalar, class Element> struct DataSet
{
DataSet(std::vector<Element> const & source);
// several generic member functions here ...
Eigen::Matrix<Scalar, ... > data;
std::vector<Element> const & source;
};
template<class Scalar>
DataSet<Scalar, SomeClass>::DataSet(std::vector<SomeClass> const & input)
{
// special impl for Element==SomeClass ...
}
SomeClass should be automatically be figured out by the compiler, when done right but i tried all meaningful combinations but still getting:
*.cpp(79) C2244 : unable to match function definition to an existing declaration
see declaration of 'DataSet<Scalar, Element>::DataSet'
I was not able to find a matching example by searching the internet yet. Thanks in advance!
EDIT:
To make it more specific, in my real world case i want to be able to define several partial specializations to the constructor with different types for Element e.g:
template<Scalar>
DataSet<Scalar, FirstClass>::DataSet(std::vector<FirstClass> const & first)
: data()
, source(first)
{
// special impl here ...
}
template<Scalar>
DataSet<Scalar, std::shared_ptr<SecondClass> >::DataSet(std::vector<std::shared_ptr<SecondClass> > const & second)
: data()
, source(second)
{
// special impl here ...
}
Redeclaring/specializing the class completely to a certain typename is not desired. Then there is little use to be a template at all. I want the solution as it is, otherwise there might be other strategies to my problem.
FIN:
Since it looks like not being possible to share the type Element between class template and constructor by only specializing the constructor (which is somehow related to an implicit specialization of the class) i removed the reference source from the class template entirely and copied the needed information into a generic container and implemented the constructors via overloads.
When defining your constructor, you didn't explicitly provide both template arguments for its class. That would need to be revised as follows:
template<typename T_Scalar, typename T_Element>
DataSet<T_Scalar, T_Element> // template args for type
::DataSet(std::vector<T_Element> const &input) // but none for constructor
{
// stuff
}
Tangentially related: Unlike methods, template arguments for classes cannot be deduced from constructor calls. That is: until C++17 comes around! woo!
The next stumbling block you faced is that template specialisations do not 'inherit' members from their primary template. It is somewhat intuitive to assume they would, but it's just not so. Until I find an official rationale, I presume it's because template arguments might make certain members totally inapplicable to a specialisation, rendering implicit 'inheritance' problematic. If so, it would've been decided to require full redeclaration / not judged worthwhile to add arcane syntax to specify which primary 'base' members are 'inherited'... when you can simply use real inheritance to ensure they are.
Anyway, what that means is that to get a partial specialisation, you need to declare the whole thing - in this case, the class and its constructor - before you can specialise that constructor's definition. You hadn't declared these ahead of time, so the compiler rightly complained that it couldn't see a declaration.
// Define specialised class
template<typename T_Scalar>
class DataSet<T_Scalar, SomeClass>
{
public:
// Declare its ctor
DataSet(std::vector<SomeClass> const &);
}
// Implement its ctor
template<typename T_Scalar>
DataSet<T_Scalar, SomeClass> // complete template args
::DataSet(std::vector<SomeClass> const &input)
{
// stuff
}
See my working example of an equivalent template class, showing general vs. specialised instantiations.
To add to your original confusion, which is fair! - note that out-of-line definitions can get very complicated indeed if a template class itself contains a template function, because then you need 2 template clauses, e.g.
template<typename TA, typename TB>
class Widget {
template<typename TC>
void accept_gadget(TC &&gadget);
};
template<typename TA, typename TB>
template<typename TC>
Widget<TA, TB>
::accept_gadget(TC &&gadget)
{
/* ... */
}
Something that will help a lot in many contexts, especially including such out-of-line template definitions, is if the proposal to allow namespace class is accepted in a future version. Very sad this didn't make it into C++17... and very odd that it was ever missing in the 1st place!
According to §14.7.3.16:
In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well.
Still, you can use std::enable_if to partial-specialize your contructor:
template <class Scalar, class Element> struct DataSet
{
template <class T>
DataSet(std::vector<T> const & input, std::enable_if_t<!std::is_same<T, SomeClass>{}> * = nullptr) {
std::cout << "Element\n";
}
template <class T>
DataSet(std::vector<T> const & input, std::enable_if_t<std::is_same<T, SomeClass>{}> * = nullptr) {
std::cout << "SomeClass\n";
}
};
But this way is restrictive:
all your conditions must be exclusives
you'll have to modify the code of your class for every new class you want to handle.
Instead, I'd advise you to use a template helper structure:
DataSet(std::vector<Element> const & input) {
Helper<Element>::do_it(input);
}
that you can specialize as you want:
template <class Element>
struct Helper {
static void do_it(std::vector<Element> const & input) {
std::cout << "General form with Element\n";
}
};
template<>
struct Helper<SomeClass> {
static void do_it(std::vector<SomeClass> const & input) {
std::cout << "SomeClass\n";
}
};
template<>
struct Helper<SomeOtherClass> {
static void do_it(std::vector<SomeOtherClass> const & input) {
std::cout << "SomeOtherClass\n";
}
};
...

deleted operator hides class operator?

I have found a very strange issue when revisiting and updating any old library. I have the following code
class bmint_tmp;
class bmfloat_tmp;
template<typename T> struct bop_return{typedef bmint_tmp type;};
template<> struct bop_return<float>{typedef bmfloat_temp type;};
class bmint
{
template<typename T> friend typename bop_return<T>::type operator+(const T& l, const bmint& r);
/** irrelevant code **/
};
template<typename T> typename bop_return<T>::type operator+(const T& l, const bmint& r)
{
return r.operator+(l);
}
template<> typename bop_return<bmint_tmp>::type operator+(const bmint_tmp& l, const bmint_tmp& r)=delete;
I have deleted this template instantiation because I prefer to get called the existing bmint_tmp::operator+, implemented as member method in another file. But, when compiling it seems that gcc dont see nothing but this deleted operator, and says:
error: use of deleted function 'typename::bigmath::bop_return::type bigmath::operator+(const T&, const bigmath::bmint&) [with T=...
I have attempted to change modifiers (remove const specification, for example), but my many attempts are unsuccessful. Can anyone help? Thanks in advance.
Yeah, if a function is deleted then it still exists (and it's even considered to be defined!), with everything that implies… you just can't actually call it.
Use enable_if, instead, so that the template specialisation cannot be instantiated at all. Then the only candidate will be the operator function you want.

C++ templates and ambiguity problem

I have a subset of a pointer class that look like:
template <typename T>
struct Pointer
{
Pointer();
Pointer(T *const x);
Pointer(const Pointer &x);
template <typename t>
Pointer(const Pointer<t> &x);
operator T *() const;
};
The goal of the last constructor is to allow to pass a Pointer of a subclass, or basically any type that is implicitly convertable to T *. This actual rule is only enforced by the definition of the constructor and the compiler can't actually figure it out by the declaration alone. If I drop it, and try to pass a Pointer<Sub> to a constructor of Pointer<Base>, I get a compile error, despite of the possible path through operator T *().
While it solves the above problem, it creates another one. If I have an overloaded function whose one overload takes a Pointer<UnrelatedClass> and the other takes Pointer<BaseClass>, and I try to invoke it with a Pointer<SubClass>, I get an ambiguity between the two overloads, with the intention, ofcourse, that the latter overload will be called.
Any suggestions? (Hopefully I was clear enough)
The cure for your problem is called SFINAE (substitution failure is not an error)
#include "boost/type_traits/is_convertible.hpp"
#include "boost/utility/enable_if.hpp"
template<typename T>
class Pointer {
...
template<typename U>
Pointer(const Pointer<U> &x,
typename boost::enable_if<
boost::is_convertible<U*,T*>
>::type* =0)
: ...
{
...
}
...
};
If U* is convertible to T* the enable_if will have a typedef member type defaulting to void. Then, everything is fine. If U* is not convertible to T* this typedef member is missing, substitution fails and the constructor template is ignored.
This solves your conversion and ambiguity problems.
In response to the comment: is_convertible looks something like this:
typedef char one; // sizeof == 1 per definition
struct two {char c[2];}; // sizeof != 1
template<typename T, typename U>
class is_convertible {
static T source();
static one sink(U);
static two sink(...);
public:
static const bool value = sizeof(sink(source()))==1;
};
Try to make the constructor in question explicit, e.g.:
template <typename t>
explicit Pointer(const Pointer<t> &x);
And/or remove the operator T *() const; - I think this one will also create an ambiguity.
EDIT
Check the std::auto_ptr interface, and compare with yours. At least they solved the ambiguity.