【问题标题】:Select a constructor based on template parameters根据模板参数选择构造函数
【发布时间】:2017-09-27 01:10:10
【问题描述】:

我想根据模板参数的值更改类函数。使用this post,所有成员函数都可以根据模板参数进行不同的编写,效果很好。问题是该示例使用函数的返回类型,因此它不适用于构造函数。基于this 帖子和this 帖子,我试过了:

// I'm using gcc 4.8.4 so have to define enable_if_t myself although 
// I guess it's not really needed

template< bool B, class T = void >
using enable_if_t = typename std::enable_if<B,T>::type;

template<class T, std::size_t CAPACITY, bool USE_THREADS = true>
class C_FIFO
{
public:
//...other ctor defs

    template<bool trigger = USE_THREADS, enable_if_t<not trigger>* = nullptr >
    C_FIFO(const C_FIFO& that):
        m_buf_capacity(CAPACITY + 1), m_in_ctr(0), m_out_ctr(0), m_wait(true)
    {
        m_buffer_data = that.m_buffer_data;
        m_in_ctr = that.m_in_ctr;
        m_out_ctr = that.m_out_ctr;
        m_wait    = that.m_wait.load();
    }
// more stuff
}

template<class T, std::size_t CAPACITY, bool USE_THREADS = true>
class C_FIFO
{
public:
//...other ctor defs

    template<bool trigger = USE_THREADS>
    //enable_if_t<not trigger>
    C_FIFO(const C_FIFO& that, enable_if_t<not trigger, bool> t = false):
        m_buf_capacity(CAPACITY + 1), m_in_ctr(0), m_out_ctr(0), m_wait(true)
    {
        m_buffer_data = that.m_buffer_data;
        m_in_ctr = that.m_in_ctr;
        m_out_ctr = that.m_out_ctr;
        m_wait    = that.m_wait.load();
    }
// other stuff
}

但在这两种情况下,编译器都会尝试使用默认的复制构造函数,该构造函数已被删除,因为该类包含不可复制的类型(互斥体和条件变量)。这两种情况似乎都应该起作用,但显然我没有看到任何东西:)。任何指针(没有双关语)将不胜感激。

【问题讨论】:

  • 喜欢this ?
  • 我也看到了那个帖子——我会试试的。我想既然我已经看过其他帖子并且它们更接近我已经在做的事情(使用 enable_if),我希望能坚持下去以保持一致性。我还在尝试围绕整个 SFINAE 范式进行思考,所以我希望了解它们为什么不起作用。
  • 该方法是否也引入了额外的复制操作?
  • 不,它没有
  • 它肯定不会——感谢上帝的参考。谢谢。该帖子中的方法有效。谢谢@PiotrSkotnicki

标签: c++ c++11 templates


【解决方案1】:

遗憾的是,构造函数不如函数灵活。

using namespace std;
struct S
{
    template<typename T>
    S(typename enable_if<is_same<T, int>::value>::type* = nullptr)
    { cout << "T is int" << endl; }
    template<typename T>
    S(typename enable_if<!is_same<T, int>::value>::type* = nullptr)
    { cout << "T is not int" << endl; }
};

//this works, T is not int
S s;

//these all don't work
auto s = S<int>();
S s<int>();
S s<int>{};

如提到的here(强调添加)

因为显式模板实参列表跟在函数模板名之后,并且因为转换成员函数模板和构造函数成员函数模板在调用时不使用函数名,所以没有办法提供显式模板实参列表 用于这些函数模板。

你能做的最好的事情是创建一个工厂函数并希望copies are elided,它还要求一个复制/移动构造函数。否则你可以传入不同类型的参数只是为了“选择”构造函数,这并不漂亮。

using namespace std;
struct S
{
    template<typename T>
    S(T*, typename enable_if<is_same<T, int>::value>::type* = nullptr);
};

template<typename T>
S make_S(typename enable_if<is_same<T, int>::value>::type* = nullptr);

S s((int*)nullptr);  //god awfully ugly
auto s = make_S<int>();  //hope for elision, must be copyable/moveable

【讨论】:

    【解决方案2】:

    我使用委托构造函数实现了@PiotrSkotnicki 的答案,但很快就遇到了与赋值运算符类似的问题(实际上问题更大,因为你不能用额外的参数重载它)。尽管我能够解决这两个问题,但稍作调整:

    template<class T, std::size_t CAPACITY, bool USE_THREADS = true>
    class C_FIFO
    {
    public:
        C_FIFO(): m_buf_capacity(CAPACITY + 1), m_in_ctr(0), m_out_ctr(0),
            m_wait(true) { }
    
        // copy constructor needs to be fancy because the mutex is not copyable or
        // movable.  Uses private helper functions to pick single or
        // multi-threaded version
    
        C_FIFO(const C_FIFO &that):m_buf_capacity(CAPACITY + 1)
        {
            copy_fifo(that, std::integral_constant<bool, USE_THREADS>{});
        }
    
        C_FIFO& operator=(const C_FIFO& that)
        {
            return copy_fifo(that, std::integral_constant<bool, USE_THREADS>{});
        }
    // other public methods here
    
    private:
        C_FIFO& copy_fifo(const C_FIFO& that, std::true_type)
        {
            std::unique_lock<std::mutex> this_lock(this->m_lock, std::defer_lock);
            std::unique_lock<std::mutex> that_lock(that.m_lock, std::defer_lock);
            std::lock(this_lock, that_lock);
    
            m_buffer_data = that.m_buffer_data;
            m_in_ctr = that.m_in_ctr;
            m_out_ctr = that.m_out_ctr;
            m_wait    = that.m_wait.load();
            return *this;
        }
    
    
        C_FIFO& copy_fifo(const C_FIFO& that, std::false_type)
        {
            m_buffer_data = that.m_buffer_data;
            m_in_ctr = that.m_in_ctr;
            m_out_ctr = that.m_out_ctr;
            m_wait    = that.m_wait.load();
            return *this;
        }
    
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-02
      • 2021-08-13
      • 1970-01-01
      相关资源
      最近更新 更多