I have a class template Foo<T>
.
I'd like to implement a non-member function Bar
that takes two Foo
s 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With