【问题标题】:Getting templated template function declaration correct正确获取模板化模板函数声明
【发布时间】:2017-09-08 23:46:50
【问题描述】:

我遇到了这样的问题,我正在尝试编译:

#include <vector>
#include <array>

struct Test
{
    template <template <typename...> class Container, typename T, typename... Args>
    void SetData(const Container<T, Args...>& data)
    {
        // compiles for vector but not array
        // 'void Test::SetData(const Container<T,Args...> &)': could not deduce template argument for 'const Container<T,Args...> &' from 'std::array<float,3>' 

    }
};


int main()
{
    Test test;
    std::vector<int> vector{ 1,2,3 };
    std::array<float, 3> arr{1.0f, 2.0f, 3.0f};

    test.SetData(vector);
    test.SetData(arr);

    return 0;
}

基本上我需要一个可以接受任意 STL 容器(更具体地说是 std::vectorstd::array)的函数签名,并且我需要在函数中也可见的类型 T(即 intfloat 在这个案例)。其他类型(分配器或std::array 大小)我不关心。

什么是正确的签名?

【问题讨论】:

  • 您将无法获得一个模板来获取所有模板,因为std::array 使用非类型模板参数。
  • @KaiserJohaan - 答案改进:在isCnt 中定义类型,其名称与type 不同(也由std::true_typestd::false_type 继承),例如containedType,它是可以简化在 T 上工作的 SFINAE 启用/禁用部分,并避免将 std::enable_if 与返回类型一起使用。

标签: c++ c++11 templates stl variadic-templates


【解决方案1】:

什么是正确的签名?

据我所知,不可能编写一个正确的签名来拦截所有容器并且只拦截容器。

但是,如果您接受编写类型特征,说明类型是否为容器并提取包含的类型(需要通用版本,std::vector 和类似 typename ... 容器的部分特化和 @987654323 的特化@;其他专业可以添加)如下isCnt

template <typename>
struct isCnt : public std::false_type
 { };

// std::array case
template <template <typename, std::size_t> class C,
          typename T, std::size_t N >
struct isCnt<C<T, N>> : public std::true_type
 { using containedType = T; };

// other container case
template <template <typename ...> class C,
          typename T0, typename ... Ts>
struct isCnt<C<T0, Ts...>> : public std::true_type
 { using containedType = T0; };

你可以如下构造setData()

模板::containedType> 无效 SetData(C 常量和数据) { // 这里的代码 }

观察setData()T = isCnt&lt;C&gt;::containedType 启用(或禁用)了SFINAE,这仅适用于容器。

以下是一个完整的工作示例

#include <array>
#include <vector>
#include <iostream>
#include <type_traits>

template <typename>
struct isCnt : public std::false_type
 { };

// std::array case
template <template <typename, std::size_t> class C,
          typename T, std::size_t N >
struct isCnt<C<T, N>> : public std::true_type
 { using containedType = T; };

// other container case
template <template <typename ...> class C,
          typename T0, typename ... Ts>
struct isCnt<C<T0, Ts...>> : public std::true_type
 { using containedType = T0; };

struct Test
 {
   template <typename C, typename T = typename isCnt<C>::containedType>
   void SetData (C const & data)
    {
      if ( std::is_same<T, int>::value )
         std::cout << "- int case" << std::endl;
      else if ( std::is_same<T, float>::value )
         std::cout << "- float case" << std::endl;
    }
 };

int main ()
 {
   Test test;
   std::vector<int> vector{ 1,2,3 };
   std::array<float, 3> arr{ { 1.0f, 2.0f, 3.0f } };

   test.SetData(vector); // print "int case"
   test.SetData(arr);    // print "float case"
   //test.SetData(0);    // compilation error
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-18
    • 1970-01-01
    • 1970-01-01
    • 2011-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多