模板类的两个类型名的模板友元函数

问题描述 投票:0回答:1

我尝试将两个参数类型名的模板函数作为模板类的友元。但我无法设法使其链接。

考虑以下示例。请注意,代码非常简化。

#include <iostream>

template <typename T>
struct S;

template <typename U, typename T>
S<U> cast(S<T> const &); //PROBLEMATIC!

template <typename T>
std::ostream& operator<< (std::ostream& os, S<T> const & s); //no problem

template <typename T>
struct S
{
public:
    S() = default;
    ~S() = default;
    S( S const & ) = default;
    S( S&& ) = default;
    S(T val) : value{val} {}

    template <typename U>
    friend
    S<U> cast(S<T> const &); //PROBLEMATIC!

    friend
    std::ostream& operator<< <T>(std::ostream& os, S<T> const & s); //no problem
private:
    T value;
};

template <typename T>
inline std::ostream& operator<< (std::ostream& os, S<T> const & s) //no problem
{ return os << s.value; }

template <typename T, typename U>
S<U> cast(S<T> const & src) //problematic!
{return {static_cast<U>(src.value)};}

int main()
{
    S<int> s1{ 10 };
    auto s2{ cast<float>(s1) }; //linker error
    std::cout << s1 << ' ' << s2;
    return 0;
}

所以,简单来说,

cast
是一个美化的转换函数。 原设计中不能改写为常规转换函数。

注意,模板

operator<<
已明确专门化,因此没有问题。然而,
cast
只能部分特化,(AFAIK)函数不允许这样做。

问题是:如何(如果)在不显式实例化的情况下实现这一目标

S<float>

我尝试删除

cast
之前的
S
的前向声明。这没有帮助。 我已经尝试过
template <typename U> friend S<U> cast<U>(S<T> const &);
。它提高了
partial specialization not allowed

确切的链接器错误:

<source>:26:10: error: function template partial specialization is not allowed
   26 |     S<U> cast<U>(S const &);
      |          ^   ~~~
1 error generated.
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/example-fd62b9.o: in function `main':
<source>:45:(.text+0x22): undefined reference to `S<float> cast<float>(S<int> const&)'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

实例

c++ templates friend
1个回答
0
投票

这是一个工作代码

#include <iostream>

template <typename T>
struct S;

template <typename T>
std::ostream& operator<<(std::ostream& os, S<T> const& s);  // no problem

template <typename T>
struct S {
 public:
  S() = default;
  ~S() = default;
  S(S const&) = default;
  S(S&&) = default;
  S(T val) : value{val} {}

  template <typename U, typename V>
  friend S<U> cast(S<V> const&);

  friend std::ostream& operator<< <T>(std::ostream& os, S<T> const& s);

 private:
  T value;
};

template <typename T>
inline std::ostream& operator<<(std::ostream& os, S<T> const& s) {
  return os << s.value;
}

template <typename U, typename T>
S<U> cast(S<T> const& src) {
  return {static_cast<U>(src.value)};
}

int main() {
  S<int> s1{10};
  auto s2{cast<float>(s1)};
  std::cout << s1 << ' ' << s2;
  return 0;
}
  1. 朋友
    cast
    的前置声明是不必要的。
  2. 为了将友元声明与实现相匹配,必须使用两个模板参数来声明友元。
  template <typename U, typename V>
  friend S<U> cast(S<V> const&);
© www.soinside.com 2019 - 2024. All rights reserved.