根据模板参数选择构造函数

时间:2017-04-28 20:17:17

标签: c++ c++11 templates

我想根据模板参数的值更改类函数。使用this帖子,所有成员函数都可以根据模板参数进行不同的编写,效果很好。问题是该示例使用函数的返回类型,因此它不能与构造函数一起使用。基于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
}

但是在这两种情况下,编译器都会尝试使用默认的复制构造函数,因为该类包含不可复制的类型(互斥和条件变量)。两种情况看起来都应该有效,但显然我没有看到任何东西:)。任何指针(没有双关语)都会受到赞赏。

2 个答案:

答案 0 :(得分:0)

可悲的是,构造函数的功能不如函数。

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,它还要求复制/移动构造函数。否则,您可以将不同类型的参数传递给&#34;选择&#34;构造函数,不是很漂亮。

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

答案 1 :(得分:0)

我使用委托构造函数实现了@ 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;
    }

};