Is it considered a good practice to use friend to define global functions within the class definition, even when the access to private members is not needed. For example
template<typename T>
class A {
public:
A(T v);
T value() const;
friend A operator+(T n, const A& a) {
return A(a.value() + n);
}
};
instead of
template<typename T>
class A {
public:
A(T v);
T value() const;
};
template<typename T>
A<T> operator+(T n, const A<T>& a) {
return A<T>(a.value() + n);
}
even though operator+ only uses value() which is public.
Is this commonly done, us is it not recommended?
There's one major advantage to friend here. When we define:
friend A operator+(T, const A&);
This is not a function template. This is just a function - a special one that can only be found by ADL. But since it's not a function template, conversions still can happen. On the flip side:
template <class T>
A<T> operator+(T, const A<T>&)
is a normal old function template with all of the normal rules regarding template type deduction.
Why does this matter? Consider:
A<double> a(4.2);
5 + a;
In the first case, this is perfectly fine. We find operator+(double, const A<double>&), the 5 gets converted to 5.0, which is an allowed conversion, and we get back A<double>(9.2).
In the second case, template deduction fails because the T deduces to different types for the two arguments. Hence, the code is ill-formed.
Related
Based on the answer in Implicit conversion when overloading operators for template classes I was able to write the following code that works perfectly fine (simplified example):
namespace my_library {
template <typename T>
struct Number {
T n;
inline Number(T n) : n(n) { }
friend Number<T> operator+(const Number<T> &a, const Number<T> &b) {
return Number<T>(a.n + b.n);
}
};
}
int main() {
return (int) (4 + my_library::Number<double>(3)).n; // returns 7
}
All I want to do is make it so that operator+ is not inlined within the definition of Number (but stays in the header file) while everything still works the same way - see the expression in the main function. Note that it requires that the integer 4 gets implicitly converted to double and then to Number<double>. I followed a comment linking to Binary operator overloading on a templated class but that solution did not work - the overloaded operator is no longer matched. Is there any way to make this work and have the body of the operator outside the struct definition? (Without complicating the operator interface or adding more overloads - in those cases I'd rather just keep it inlined.)
You can do it like this:
template <typename T>
struct Number {
// ...
template <class U>
friend Number<U> operator+(const Number<U> &a, const Number<U> &b);
};
template <typename U>
Number<U> operator+(const Number<U> &a, const Number<U> &b) {
return Number<U>(a.n + b.n);
}
In this example, operator+ will be a friend of all Number specializations even when the types don't match. This might be a broader friendship than you intended, but is the simplest way to achieve your objective of moving the definition of operator+ outside the definition of Number. Note that when a friend is not defined inline, you lose the benefit of having it as a "hidden friend". (A hidden friend can only be found via argument-dependent lookup, which means that the compiler will typically not have to consider it as a candidate function in most cases where it is not intended to be used.)
If you want each specialization of operator+ to only be a friend of one particular Number specialization where the types match, it is more complicated. You have to forward-declare the operator+ template in order to prevent the friend declaration from declaring a non-template function, and you also have to forward-declare Number so that it can be used in the operator+ forward declaration:
template <typename T> struct Number;
template <typename T>
Number<T> operator+(const Number<T>&, const Number<T>&);
template <typename T>
struct Number {
// ...
friend Number<T> operator+<>(const Number<T>&, const Number<T>&);
};
template <typename T>
Number<T> operator+(const Number<T> &a, const Number<T> &b) {
return Number<T>(a.n + b.n);
}
I wrote simple class and define one copy constructor.
Then add friend equal comparison operator and compare int with Int
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
friend bool operator==(const Int<T>& f, const Int<T>& s) {
return f.value == s.value;
}
};
int main() {
int a;
Int<int> x(a);
x == a;
}
Compiled successfully.
If I turn the friend bool operator==(const Int<T>& f, const Int<T>& s); into a non-friend template. I get a compiler error:
error: no match for 'operator==' (operand types are 'int' and 'Int<int>'
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
};
template <class T>
bool operator==(const Int<T>& f, const Int<T>& s) {
return f.value == s.value;
}
int main() {
int a;
Int<int> x(a);
x == a;
}
Does it mean that friend functions allow specific conversions?
5 == x works too.
Does the c++ friend keyword mean more then access to private?
Depending on context, it can have more implications, yes. For instance, a friend function defined inline, with no other declaration, can only be found by argument dependent lookup, even though it's a member of the enclosing namespace:
namespace foo {
struct bar {
friend void baz(bar const&) {}
};
}
int main() {
foo::bar bar;
// foo::baz(bar); // ill-formed, no member baz in foo
baz(bar); // Okay, it *can* be found by ADL
};
That is not directly related to your question, but that is how the friend operator== is looked up. And that said friend is also not a template itself. When you instantiate Int<int>, this "injects" a free operator== function - which is, again, not a template - into the namespace Int is a member of. When that operator function is looked up (by ADL) for the purposes of doing x == a, the compiler will happily consider implicitly converting a to Int<int>, because we can do implicit conversions to match regular free functions.
And speaking of conversions...
I wrote simple class and define one copy constructor.
You did not. That is a user-defined constructor taking an int const& argument, not an Int<int> const& like a copy constructor would take. You defined a converting constructor (because it's not explicit), which is exactly how the compiler can convert a to Int<int> above.
If I turn...
In your second version the operator is a template. It's still looked up by ADL. But template argument deduction only considers the exact type of the arguments. I.e, both arguments to operator== must be directly able to bind to Int<T> const& for some T. An int cannot be bound directly to Int<int> const&, it requires a conversion. So it doesn't match the sort of argument the template needs to do template argument deduction. Therefore the template cannot be instantiated, and is not a candidate.
Does it mean that friend functions allows specific conversions?
No, it's not the friendship. It's the template vs non-template business. You can define an operator== without friendship, but it has to be per-instantiation of Int:
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
};
bool operator==(const Int<int>& f, const Int<int>& s) {
return f.value == s.value;
}
That will make your main well-formed too. But as you noticed, it's not very useful having to declare those individually, so many code bases will use the friend version to "inject" this free function automatically.
I have a template class A
template <unsigned int m>
class A
{
public:
A(int) {}
};
Which has a constructor from int. And I have an operation:
template<unsigned int m>
A<m> operator+(const A<m>&, const A<m>&)
{
return A<m>(0);
}
But when I call:
A<3> a(4);
A<3> b = a + 5;
A<3> c = 5 + a;
I would like int to be implicitly converted to A, but compilers throws error.
Is there any elegant way to enable implicit conversion without using such solutions as:
a + A<m>(5)
operator+<3>(a, 5)
The solution is already shown in this answer. Now, more about the problem...
The problem in your code is how overload resolution is performed. When a template function is considered for overload resolution the compiler will perform type deduction on the arguments and come up with a type substitution that matches the call or else it fails to apply that template, removes it from the set of potential candidates and continues over. The problem at this point is that type deduction only deduces exact matches (with possible extra const/volatile qualification). Because the matching is exact, the compiler will not use any conversion (again, other than cv).
The simplest example of this happens with std::max and std::min functions:
unsigned int i = 0;
std::min( i, 10 ); // Error!
Type deduction will deduce the T in template <typename T> min( T const &, T const & ) to be unsigned for the first argument but int for the second they differ and the compiler will discard this template function.
The solution proposed in the answer is using a feature of the language that enables you to define a non-member friend function inside the class definition. The advantage with templates is that for every (different) instantiation of the template, the compiler will create a free non-template function at namespace level that has the signature obtained by substituting the real types of the instantiation in the friend declaration:
template <typename T>
class test {
friend test operator+( test const & lhs, test const & rhs ) { // [1]
return test();
}
}
test<int> t; // [2]
In the example above, the compiler allows you to add the definition of the friend function inside the class scope at [1]. Then when you instantiate the template in [2], the compiler will generate a free function:
test<int> operator+( test<int> const & lhs, test<int> const & rhs ) {
return test<int>();
}
The function is defined always, whether you use it or not (this differs to the template class member functions, that are instantiated on demand).
The magic here has multiple sides to it. The first part is that it generically you are defining non-template functions for each and all of the instantiated types, so you gain genericity and at the same time the advantage of overload resolution being able to use this function when the arguments are not perfect matches.
Because it is a non-template function, the compiler is able to call implicit conversions on both arguments, and you will get your expected behavior.
Additionally, a different type of magic goes on with lookup, as the function so defined can only be found by argument dependent lookup unless it is also declared at namespace level, which in our case cannot be done in a generic way. The implication of this might be good or bad, depending on how you want to consider it...
Because it can only be found by ADL it will not be considered unless at least one of the arguments is already of the desired type (i.e. it will never be used performing conversions to both arguments). The downside is that it is impossible to refer to the function unless you are actually calling it, and that means that you cannot obtain a function pointer.
(More on template friendship here, but note that in this particular case, all the other variants will fail to perform implicit conversions).
Every attempt to provide an operator using templates will need at least one second overload. But you can avoid that by defining the operator inside the class:
template <unsigned int m>
class A
{
public:
A(int) {}
inline friend A operator+(const A& a, const A& b) { return A(0); }
};
Works for both, a+5 and 5+a.
Add this operator
template<unsigned int m>
A<m> operator+(const A<m>&, const int&)
{
return A<m>(0);
}
OR try this
template <unsigned int m>
class A
{
friend const A operator+(const A& a, const A& b) { return A(0); }
public:
A(int) {}
// OR FOR UNARY
// const A operator+(const A &a) const {return A(0);}
};
int main(){
A<3> a(4);
A<3> b = a + 5;
A<3> c = 5 + a;
}
You could try adding an additional "policy" type argument to the template for your A class that will determine the actual desired conversion type. For instance:
template <unsigned int m, typename ConvVal = int>
class A
{
public:
typedef ConvVal conv_val;
A(ConvVal) {}
};
template<template <unsigned int, class U> class T, unsigned int m, typename U>
T<m, U> operator+(const T<m, U>&, const T<m, U>&)
{
return T<m, U>(0);
}
template<template <unsigned int, class U> class T, unsigned int m, typename U>
T<m, U> operator+(const T<m, U>&, const typename T<m, U>::conv_val&)
{
return T<m, U>(0);
}
template<template <unsigned int, class U> class T, unsigned int m, typename U>
T<m, U> operator+(const typename T<m, U>::conv_val&, const T<m, U>&)
{
return T<m, U>(0);
}
int main()
{
A<3> a(4);
A<3> b = a + 5;
return 0;
}
Now your A class will take an additional template argument that defaults to an int type, and it defines the actual type that you will allow automatic conversions from. You only need to overload the operator+ function three times, once for the version without the conversion value that will take explicit classes of type A<m, T>, and another for the two versions of operator+ that will take conversion types. In the above code I've generalized this with more generic types so that this can be done with pretty much any other class that has the proper template signature, and defines a conv_val typedef.
This is more of a design question.
I have a template class, and I want to add extra methods to it depending on the template type. To practice the DRY principle, I have come up with this pattern (definitions intentionally omitted):
template <class T>
class BaseVector: public boost::array<T, 3>
{
protected:
BaseVector<T>(const T x, const T y, const T z);
public:
bool operator == (const Vector<T> &other) const;
Vector<T> operator + (const Vector<T> &other) const;
Vector<T> operator - (const Vector<T> &other) const;
Vector<T> &operator += (const Vector<T> &other)
{
(*this)[0] += other[0];
(*this)[1] += other[1];
(*this)[2] += other[2];
return *dynamic_cast<Vector<T> * const>(this);
}
virtual ~BaseVector<T>()
{
}
}
template <class T>
class Vector : public BaseVector<T>
{
public:
Vector<T>(const T x, const T y, const T z)
: BaseVector<T>(x, y, z)
{
}
};
template <>
class Vector<double> : public BaseVector<double>
{
public:
Vector<double>(const double x, const double y, const double z);
Vector<double>(const Vector<int> &other);
double norm() const;
};
I intend BaseVector to be nothing more than an implementation detail. This works, but I am concerned about operator+=. My question is: is the dynamic cast of the this pointer a code smell? Is there a better way to achieve what I am trying to do (avoid code duplication, and unnecessary casts in the user code)? Or am I safe since, the BaseVector constructor is private?
EDIT:
Sorry, yes I have virtual dtor, but I forgot to paste it, the code doesn't compile without it.
I would recommend that you consider an alternative approach (note that in the below examples, I have simplified the code to the bare minimum required to demonstrate the alternative approaches).
First, consider the Curiously Recurring Template Parameter (CRTP):
template <typename T, typename DerivedVector>
struct BaseVector
{
DerivedVector& operator+=(DerivedVector const& other)
{
return static_cast<DerivedVector&>(*this);
}
};
template <typename T>
struct Vector : BaseVector<T, Vector<T>>
{
};
Since you always know what the derived type is, a static_cast is sufficient. If Vector<T> is the only class whose base is BaseVector<T> and if you are guaranteed that the T parameters are always the same, then strictly speaking, the CRTP parameter is unnecessary: you always know what the derived type is, so a static_cast is safe.
Alternatively, consider that operators need not be member functions, so you could declare non-member operator function templates:
template <typename T, typename DerivedVector>
struct BaseVector
{
};
template <typename T>
struct Vector : BaseVector<T, Vector<T>>
{
};
template <typename T>
Vector<T>& operator+=(Vector<T>& self, Vector<T> const& other)
{
return self;
}
While the latter is preferable for operators, it won't work for ordinary, nonoperator member functions, so the CRTP approach would be preferable for those.
Yes, from a technical point of view it is OK. However, in order for the dynamic_cast to work your base class needs to be polymorphic. So you need to make at least the destructor (pure) virtual.
I also want to add that instead of:
// potential null dereference
return *dynamic_cast<Vector<T> * const>(this);
it is safer to write:
// potential std::bad_cast exception
return dynamic_cast<Vector<T> & const>(*this);
To answer your original question:
Is there a better way to achieve what I am trying to do (avoid code duplication, and unnecessary casts in the user code)?
Yes. Read about static polymorphism, curiously recurring template pattern and policy-based class design if you want to learn more.
None of your methods are virtual. Without any virtual methods, the compiler won't add any run-time type information. Without RTTI, dynamic_cast will not work.
I think a better way to accomplish this is the pimpl idiom. As you say, BaseVector is just an implementation detail. As such, clients of your class should have no knowledge of it (which leaves you free to change it).
In this case, this would entail having Vector contain a BaseVector rather than inherit from it. It would then define its own arithmetic assignment operators, which would forward to BaseVector.
This does not violate DRY, because there is still only one version of the implementation details, and they reside in BaseVector. Repeating the interface is perfectly fine.
This is an old question, but I recently had to solve this same problem and then happened to stumble across this, so I thought I'd answer.
I used a type wrapper in order to have the specialisation 'derive from itself':
template <class T>
struct type_wrapper;
template <class T>
struct unwrap_type
{
typedef T type;
};
template <class T>
struct unwrap_type<type_wrapper<T>>
{
typedef T type;
};
template <class WrappedT>
class Vector: public boost::array<typename unwrap_type<WrappedT>::type, 3>
{
typedef typename unwrap_type<WrappedT>::type T;
protected:
Vector(const T x, const T y, const T z);
public:
bool operator == (const Vector &other) const;
Vector<T> operator + (const Vector &other) const;
Vector<T> operator - (const Vector &other) const;
Vector<T> &operator += (const Vector &other)
{
(*this)[0] += other[0];
(*this)[1] += other[1];
(*this)[2] += other[2];
return static_cast<Vector<T> &>(*this);
}
}
template <>
class Vector<double> : public Vector<type_wrapper<double>>
{
public:
Vector(const double x, const double y, const double z);
Vector(const Vector<int> &other);
double norm() const;
};
That way, you don't need any redundant classes - except for the type wrapper and metafunction, which are reusable.
I have a class template Foo<T>.
I'd like to implement a non-member function Bar that takes two Foos and returns a Foo. I want Bar to be a non-member because it will be more natural for callers to write Bar(f1, f2) than f1.Bar(f2). I also want Bar to be inline because the calculation is trivial and frequent.
template <typename T>
inline Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs) {
...
}
The trick is Bar needs access to Foo's private data. I'd prefer not to have accessors to the private data--there's no good reason to expose the private data to users. So I'd like to make Bar a friend of Foo.
template <typename T>
class Foo {
...
private:
T w, x, y, z;
friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
};
Here's where I run into trouble. The compiler complains:
The inline specifier cannot be used when a friend declaration refers to a specialization of a function template.
Is this rule imposed by the standard or is it specific to MSVC++?
Here's what I've tried:
Make Bar a const public member function, and then to declare a non-member version that simply returns lhs.Bar(rhs). This seems the least hacky solution.
Remove the inline hint, knowing that the compiler is going to decide about inlining regardless of the hint. Does this then run afoul of the one-definition rule? It will still have to be defined in a header file because it's a function template.
Declare the member function with a dummy template type:
template <typename T>
class Foo {
...
private:
T w, x, y, z;
// Note that this declaration doesn't actually use Dummy. It's just there to
// satisfy the compiler.
template <typename Dummy>
friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
};
I'm not entirely sure why that works, but it does satisfy the compiler.
Is there a better solution?
If the calculation is trivial, I would write:
template <typename T>
class Foo {
...
private:
T w, x, y, z;
public:
friend Foo Bar(const Foo &lhs, const Foo &rhs) {
...
}
};
This doesn't fall foul of the ODR - it's an inline function with external linkage (3.2/5 excludes this from the ODR subject to the definitions being identical, 7.1.2/3 says that it's inline).
However, this doesn't define a function template Bar<T>, it just defines a set of function overloads for Bar. There may be some reason, unstated in the question, that means this won't work for you because you actually need the template.
I like option 1 the best:
template <typename T>
inline Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs) {
return lhs.Bar(rhs);
}
template <typename T>
class Foo {
...
Foo<T> Bar(const Foo<T> &other) const;
private:
T w, x, y, z;
};
Then the functionality is safely contained within the class, but you provide a wrapper function for convenience.
Bar is a template, so it has to be a template in the friend declaration as well.
You don't necessarily have to use a dummy parameter, but could rather use
template <typename U>
friend Foo<U> Bar(const Foo<U> &lhs, const Foo<U> &rhs);
You cannot use T as the template parameter here, as there is already an outer T in scope.