【问题标题】:Variadic template function specialization in a template class模板类中的可变模板函数特化
【发布时间】:2021-01-04 20:49:55
【问题描述】:

我正在尝试实现自己的 SmartPointer 类,并且在初始工作版本之后,我已经开始改进代码,现在面临一个我无法解决的问题。

这是第一个版本:

template<class T>
class SmartPointer
{
private:
    T* ptr;
public:
    explicit SmartPointer(T* p = nullptr):ptr(p){}
    ~SmartPointer(){delete(ptr);}
    T& operator*(){return *ptr;}
    T* operator->(){return ptr;}
};

我的问题是我必须调用它指定两次,这将是例如。 “int”类型的指针:

SmartPointer<int> intSP(new int());

所以我尝试在 SmartPointer 类的构造函数中创建一个模板构造函数,方法是将其更改为:

template<typename... Args>
explicit SmartPointer(Args... args):ptr(new T(args...)){};

在我提供至少一个参数之前,这可以正常工作。但是当没有提供参数时,整个类开始根本不工作。 (当我从中创建了一个实例并尝试分配一个值时,它会抛出以下错误:“assignment of read-only location '* intSP'”。

所以我试图进一步复杂化它,在参数包的大小上使用 enable_if,不幸的是,结果与前一种情况相同。由于某种原因, enable_if 似乎根本没有做任何事情:

    template<typename... Args,
             typename = typename std::enable_if<(sizeof...(Args)>0u)>::type>
    explicit SmartPointer(Args... args):ptr(new T(args...)){
        cout << "constructor with arguments" << endl;
    };
    template<typename... Args,
             typename = typename std::enable_if<(sizeof...(Args)==0u)>::type>
    explicit SmartPointer():ptr(new T()){
        cout << "constructor without args" << endl;
    };

最后是完整的代码,有一些概述:

#include <iostream>

using namespace std;
#define var2str(var) #var
template<class T>
class SmartPointer
{
private:
    T* ptr;
public:
    template<typename... Args,
             typename = typename std::enable_if<(sizeof...(Args)>0u)>::type>
    explicit SmartPointer(Args... args):ptr(new T(args...)){
        cout << "constructor with arguments" << endl;
    };
    template<typename... Args,
             typename = typename std::enable_if<(sizeof...(Args)==0u)>::type>
    explicit SmartPointer():ptr(new T()){
        cout << "constructor without arguments" << endl;
    };
    ~SmartPointer(){delete(ptr);}
    T& operator*(){return *ptr;}
    T* operator->(){return ptr;}
};

int main(int, char**) {
    SmartPointer<int> intSP(5);//new int());

    cin>>*intSP;
    cout << *intSP << " stored in "<< var2str(intSP) << endl;
}

【问题讨论】:

  • 你知道deduction guides in C++17怎么用吗?
  • “但是当没有提供参数时,整个类开始根本不工作” - 你确定不是“最令人头疼的解析问题”吗?我的意思是……你写过SmartPointer&lt;int&gt; intSP(); 还是SmartPointer&lt;int&gt; intSP{};
  • 我读了三次,但无法理解问题所在...请显示MCVE
  • 可能有点离题但最好用:explicit SmartPointer(Args &amp;&amp;... args) : ptr( new T( forward&lt;Args&gt;( args )... ) ) {}?
  • 带有std::enable_if_t&lt;(sizeof...(Args)==0u)&gt; 的构造函数是迂腐的UB,因为唯一有效的特化是空包。

标签: c++ variadic-templates sfinae template-specialization parameter-pack


【解决方案1】:

我想您的问题(使用单个构造函数)是由“令人头疼的解析”引起的(here 描述了“最令人头疼的解析问题”,该问题的一个更引人注目的版本)。

我的意思是......如果你写

SmartPointer<int> intSP();

编译器将其解释为函数声明。

如果你想初始化一个不带参数的变量,你可以使用括号

SmartPointer<int> intSP{};

或者没有括号

SmartPointer<int> intSP;

我想下面的例子应该很有用

#include <iostream>

template <typename T>
class SmartPointer
 {
   private:
      T * ptr;

   public:
      template <typename... Args>
      explicit SmartPointer (Args && ... args)
         : ptr{ new T{ std::forward<Args>(args)... } }
       { }

      ~SmartPointer ()
       { delete(ptr); }

      T & operator* ()
       { return *ptr; }

      T * operator-> ()
       { return ptr; }
 };

int main ()
 {
   SmartPointer<int> intSP1; // OK
   //SmartPointer<int> intSP2(); // Error: vexing parse
   SmartPointer<int> intSP3{}; // OK
   SmartPointer<int> intSP4{5}; // OK
   SmartPointer<int> intSP5(5); // OK (no more vexing parse)
 }

【讨论】:

  • 我认为 最令人头疼的解析 保留给更复杂的声明,这里它不是 most ,而只是一个令人头疼的解析.. .
  • @Jarod42 - 行动!我确信更简单的形式也被定义为“最令人烦恼的解析”。已更正。谢谢。
  • 谢谢!这起到了神奇的作用。实际上我从来没有听说过令人烦恼的解析。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-26
  • 2017-10-15
  • 2011-06-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多