我尝试将两个参数类型名的模板函数作为模板类的友元。但我无法设法使其链接。
考虑以下示例。请注意,代码非常简化。
#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)
这是一个工作代码
#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;
}
cast
的前置声明是不必要的。 template <typename U, typename V>
friend S<U> cast(S<V> const&);