简体   繁体   中英

Friend functions of a class template

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM