【问题标题】:define non-template function outside a templated class在模板类之外定义非模板函数
【发布时间】:2020-01-24 18:49:56
【问题描述】:

我正在学习模板类的非模板友元函数和模板友元函数。所以我尝试了下面的代码:

#include <iostream>   


template<typename T>
class  cl
{
private :
    T val;
public:
    cl()= default;
    explicit cl(T v) : val(std::move(v)) {}    

    friend void non_template_friend(cl m);
};

template <typename T>
void non_template_friend(cl<T> m)  { std::cout << m.val << std::endl;}


int main()
{

    cl<int> c(10);
    non_template_friend(c);
    return 0;
}

所以当我编译时我得到了:undefined reference tonon_template_friend(cl)' ` 所以要解决这个问题,我必须像这样在类定义中移动友元函数定义:

template<typename T>
class  cl
{
private :
    T val;
public:
    cl()= default;
    explicit cl(T v) : val(std::move(v)) {}    

    friend void non_template_friend(cl m) { std::cout << m.val << std::endl;}
};

但我想知道,有什么技巧可以在类定义之外定义朋友函数吗?

谢谢。

【问题讨论】:

标签: c++ templates friend-function template-classes


【解决方案1】:

如果你想在类之外定义,它必须是一个模板函数,因为它必须能够接受任何类型的c1

您可以通过前向声明类和函数来实现这一点。

#include <iostream>

template<typename T>
class  cl;

template<typename T>
void non_template_friend(cl<T> m);

template<typename T>
class  cl
{
private :
    T val;
public:
    cl()= default;
    explicit cl(T v) : val(std::move(v)) {}    

    friend void non_template_friend<T>(cl m); //Now we can refer to a specific instatiation of the template  here
};

template <typename T>
void non_template_friend(cl<T> m)  { std::cout << m.val << std::endl;}


int main()
{

    cl<int> c(10);
    non_template_friend(c);
    return 0;
}

【讨论】:

  • 没问题。这有点难看,但它可以完成工作。 AFAIK 没有更清洁的方法可以做到这一点。
  • 我有一个问题;在 C++ inSights 中:生成的代码显示了同一个专用友元函数的两个定义。怎么会有两个相同的定义?
  • 我无法回答为什么,但我知道编译器可以对同一个模板有多个定义。通常来自每个使用它的 TU。然后链接器将丢弃除一个之外的所有它们并假设它们是相同的(如果它们不是,那就是UB)。 inline 也会发生同样的事情。
  • template&lt;typename T&gt; void non_template_friend(..)。现在名字好像错了……
【解决方案2】:

在第一个程序中

template<typename T>
class  cl
{
private :
    T val;
public:
    cl()= default;
    explicit cl(T v) : val(std::move(v)) {}    

    friend void non_template_friend(cl m);
};

template <typename T>
void non_template_friend(cl<T> m)  { std::cout << m.val << std::endl;}

你声明了一个非模板友元函数,但是你声明并定义了一个同名的模板函数/

非模板友元函数声明意味着如果您必须为模板类的特化提供一组重载的非模板函数/

这是一个演示程序。

#include <iostream>
template<typename T>
class  cl
{
private :
    T val;
public:
    cl()= default;
    explicit cl(T v) : val(std::move(v)) {}    

    friend void non_template_friend(cl m) ;
};

void non_template_friend( cl<int> m)  { std::cout << m.val << std::endl;}
void non_template_friend( cl<double> m)  { std::cout << m.val << std::endl;}

int main() 
{
    cl<int> c(10);
    non_template_friend(c);

    cl<double> c2( 20.2 );
    non_template_friend(c2);


    return 0;
}

程序输出是

10
20.2

即在模板类中,非模板友元函数声明实际上是声明了一组重载的非模板函数。

【讨论】:

  • 所以如果我理解这个概念,如果我想让朋友成为模板类的非模板函数,我有 1)在类中编写定义或 2)在内部声明并强制定义它的所有特殊版本。
  • @Blood-HaZaRd 不需要为类的所有特化声明非模板友元函数。仅声明将在程序中使用的那些非模板友元函数就足够了。如果您将在一个类中定义一个非模板友元函数,那么您将只有一个相同的定义/即您将无法“专门化”非模板友元函数。
  • 是的,我的意思是 :) 仅适用于使用过的类型 ^ ^.
  • @Blood-HaZaRd 您认为最好的答案不是指非模板友元函数。在他的示例中,他声明了一个模板友元函数。它与非模板友元函数不同。
  • @super 例如,假设我们有两个函数 template void f( T t );和无效 f( int );如果我们想为 int 类型的参数调用模板函数,我们必须至少编写 f( x );如果我们只写 f(x);然后调用非模板函数。所以我们使用术语“模板函数”和“非模板函数”。对于这个调用 f( x ),我们说的是调用了模板函数。
猜你喜欢
  • 2023-03-13
  • 1970-01-01
  • 2022-07-22
  • 2011-07-30
  • 1970-01-01
  • 2020-08-09
  • 1970-01-01
  • 1970-01-01
  • 2011-06-07
相关资源
最近更新 更多