【问题标题】:How to enforce constraints between template and template template parameters in C++17如何在 C++17 中强制模板和模板模板参数之间的约束
【发布时间】:2017-10-13 06:16:04
【问题描述】:

我有以下可以编译的代码(GCC7、C++17):

template<typename T>
struct NDArrayHostAllocatorNew
{
    static T* allocate(std::size_t size) {
        return new T[size];
    }

    static void deallocate(const T* ptr){
        delete [] ptr;
    }
};

template<typename T, template<typename TT> typename Alloc>
class NDArrayHost
{
public:
    typedef Alloc<T> allocator_type;
    NDArrayHost(std::size_t size);
private:
    T* m_data;
};

template<typename T, template<typename TT> typename Alloc>
NDArrayHost<T, Alloc>::NDArrayHost(std::size_t size)
{
    m_data = allocator_type::allocate(size);
}

这是我的问题:

  • 如果我使用T 而不是TT,我会收到一个错误,即T 会遮蔽另一个。很公平,但就我而言,我希望T 与TT 相同。我该如何执行?我想我可以以某种方式使用std::enable_if 和std::is_same?但在那种情况下,代码会变得过于繁琐。有什么不那么麻烦的解决方案吗?

  • 我几乎看不到带有模板模板参数的代码。我是否在做一些不被认为是好的做法?

  • 我不太喜欢这个解决方案的语法。有没有更好的方法来做同样的事情,但代码更简洁/更简单?

  • 虽然带有模板模板参数的代码非常难看,但很明显可以理解这段代码的作用:它只允许用户指定他/她自己的机制来为NDArrayHost 对象分配内存。尽管这符合一个完全不同/单独的问题:如果您认为我完全错误地解决了这个问题,请随时向我指出一个更好的解决方案(只要不像 Thrust 那样非常复杂。

【问题讨论】:

  • "我希望 T 和 TT 一样" 这没有意义。您的用户为 NDArrayHost 提供 T。 NDArrayHost 中的你 为 Alloc 提供 TT。如果您希望 TT 与 T 相同,只需将 T 作为参数传递给 Alloc。
  • TT 是一个哑参数,写成“template typename Alloc”也有同样的效果。您也不能将 TT 用于任何目的,基本上甚至像 template typename Alloc> class NDArrayHost { using UU = TT; };是非法的。
  • 问题是关于模板模板,与 C++17 标准无关。你可以用 C++11 编译这个问题和我迄今为止看到的答案。

标签: c++ templates template-templates


【解决方案1】:

方法是根据T 和Alloc 类型声明基本模板,然后只提供合法的部分特化。

#include <cstddef>
#include <memory>

template<typename T>
struct NDArrayHostAllocatorNew
{
    static T* allocate(std::size_t size) {
        return new T[size];
    }

    static void deallocate(const T* ptr){
        delete [] ptr;
    }
};

/*
 * declare the base template in terms of T and allocator
 */
template<typename T, typename Alloc>
class NDArrayHost;

/*
 * only provide legal specialisations
 */
template<class T, template<class> class Alloc>
class NDArrayHost<T, Alloc<T>>
{
public:
    typedef Alloc<T> allocator_type;
    NDArrayHost(std::size_t size);
private:
    T* m_data;
};

template<class T, template<class> class Alloc>
NDArrayHost<T, Alloc<T>>::NDArrayHost(std::size_t size)
{
    m_data = allocator_type::allocate(size);
}

如果我们愿意,我们可以添加一个专业化以在 T 不匹配时提供诊断:

/* specifically disallow illegal specialisations */
template<class T, class U, template<class> class Alloc>
class NDArrayHost<T, Alloc<U>>
{
    static_assert(std::is_same<T, U>(), "meh");
};

测试...

int main()
{
    NDArrayHost<int, NDArrayHostAllocatorNew<int>> h(10);

    // fails with static assert
    // NDArrayHost<int, NDArrayHostAllocatorNew<double>> h2(10);
}

【讨论】:

    猜你喜欢
    • 2021-09-04
    • 2022-01-22
    • 2021-03-08
    • 2021-04-17
    • 2021-10-22
    • 1970-01-01
    • 2019-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多