Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 快速模板阵列重置方法的实现_C++_Templates_Metaprogramming_Typetraits - Fatal编程技术网

C++ 快速模板阵列重置方法的实现

C++ 快速模板阵列重置方法的实现,c++,templates,metaprogramming,typetraits,C++,Templates,Metaprogramming,Typetraits,我有一个带有重置方法的模板化数组类。我想优化重置代码,在POD上使用memset,在非POD上调用用户提供的重置 我想要1个相同的名称用于方法reset,并根据模板参数使用相关的实现,如果使用非pod类型T而没有reset函数,则需要2个编译时错误 template <typename T> class CArray { private: T* array; size_t size; public: void reset() { memset(

我有一个带有重置方法的模板化数组类。我想优化重置代码,在POD上使用memset,在非POD上调用用户提供的重置

我想要1个相同的名称用于方法reset,并根据模板参数使用相关的实现,如果使用非pod类型T而没有reset函数,则需要2个编译时错误

template <typename T>
class CArray {
private:
    T* array;
    size_t size;
public:
    void reset() {
        memset(array, 0, size);
    }
    void reset() {
        for (size_t i=0; i<size; ++i)
            array[i].reset();
    }
}

CArray<int> arr1;
arr1.reset();                       -> will use memset and be fast
struct t2 { int* mem; void reset() {} };
CArray<t2> arr2;
arr2.reset();                      -> will call t2.reset for each element
struct t3 { int* mem; };
CArray<t3> arr3;
arr3.reset();                      -> should fail compilation since t3.reset() is missing
我尝试过使用type_traits,但我不确定这是否是正确的方向,它是否有助于编译时检查?

尝试在pod上强制使用memset似乎是一种毫无意义的优化

#include <array>
#include <cstring>

struct bar
{
  int i;
  int j;
};

std::array<bar, 4> test;

void foo()
{
  memset(&test, 0, sizeof test);
}

void foo2()
{
  test.fill(bar());
}
只需专注于编写易于理解的代码,并让编译器负责优化。只要类有一个默认构造函数,就不需要使用SFINAE

对于您的类,reset方法可以按如下方式工作

void reset() {
  std::fill_n(array, size, T());
}
在我看来,试图在pod上强制使用memset似乎是一种毫无意义的优化

#include <array>
#include <cstring>

struct bar
{
  int i;
  int j;
};

std::array<bar, 4> test;

void foo()
{
  memset(&test, 0, sizeof test);
}

void foo2()
{
  test.fill(bar());
}
只需专注于编写易于理解的代码,并让编译器负责优化。只要类有一个默认构造函数,就不需要使用SFINAE

对于您的类,reset方法可以按如下方式工作

void reset() {
  std::fill_n(array, size, T());
}
省略了各种标题


省略了各种标题

不可能在类模板的非模板成员函数上使用SFINAE,因为这将部分地专门化函数,这是由于dyp的存在而不允许的

然而,正如那篇文章所建议的,您可以非常轻松地使用标记分派

演示代码。注意,我已经将数组更改为使用std::vector进行内存管理,以使我的演示更简单。实际上,不清楚为什么您的数组不这样做

#include <iostream>
#include <vector>
#include <string>
#include <type_traits>

struct Baz
{
    void reset() { std::cout << "Baz reset" << std::endl; }
    Baz(int x = 1) { }
};

template <typename T>
struct CArray {   
    std::vector<T> ptr;

    void reset()
    {
        do_reset( std::is_pod<T>{} );
    }

private:
    void do_reset(std::true_type) { std::fill(ptr.begin(), ptr.end(), T()); }
    void do_reset(std::false_type) { for (auto &x : ptr) x.reset(); }
};

int main()
{
    CArray<int> x;
    x.ptr.push_back(1);
    x.reset();      // OK, no output

    CArray<std::string> y;
    // y.reset();   // compilation error - std::string has no member "reset"

    CArray<Baz> z;
    z.ptr.push_back( Baz() );
    z.reset();      // OK, output "Baz reset"
}

在类模板的非模板成员函数上使用SFINAE是不可能的,因为这将部分地专门化函数,这是不允许的,这要感谢dyp for

然而,正如那篇文章所建议的,您可以非常轻松地使用标记分派

演示代码。注意,我已经将数组更改为使用std::vector进行内存管理,以使我的演示更简单。实际上,不清楚为什么您的数组不这样做

#include <iostream>
#include <vector>
#include <string>
#include <type_traits>

struct Baz
{
    void reset() { std::cout << "Baz reset" << std::endl; }
    Baz(int x = 1) { }
};

template <typename T>
struct CArray {   
    std::vector<T> ptr;

    void reset()
    {
        do_reset( std::is_pod<T>{} );
    }

private:
    void do_reset(std::true_type) { std::fill(ptr.begin(), ptr.end(), T()); }
    void do_reset(std::false_type) { for (auto &x : ptr) x.reset(); }
};

int main()
{
    CArray<int> x;
    x.ptr.push_back(1);
    x.reset();      // OK, no output

    CArray<std::string> y;
    // y.reset();   // compilation error - std::string has no member "reset"

    CArray<Baz> z;
    z.ptr.push_back( Baz() );
    z.reset();      // OK, output "Baz reset"
}

boost有一个enable_if,POD ness maby上的某种SFINAE?你可以在std::Pody上使用SFINAE,这可能是因为你想要的是“可复制的”而不是POD。不管怎样,C++14有一系列有趣的模板,比如is_pod、is_琐碎地_copyable等等。实现只是一个练习,等等……这与user657267的观点一致,即memset可能等于或比std::fill差;另一个选项是通过SFINAE调用reset(如果存在),如果没有,则调用std::fill(如果没有)。boost有一个enable_,如果在POD ness maby上使用某种SFINAE?您可以在std::pody上使用SFINAE。您可能希望“简单可复制”而不是POD。不管怎样,C++14有一系列有趣的模板,比如is_pod、is_琐碎地_copyable等等。实现只是一个练习,等等……这与user657267的观点一致,即memset可能等于或比std::fill差;另一个选项是通过SFINAE调用reset(如果存在),如果不存在则调用std::fill(可能为true);但是他想调用成员函数。为非POD重置,所以他的问题remains@MattMcNabb也许吧,虽然我认为一旦你不再需要区分POD和非POD,假设他想将包含的数据重置为默认状态,那么问题就消失了,也就是说,他应该为更复杂的类提供默认构造函数,而不是重置函数。这是c++11的一个惊人特性。太糟糕了,我受到VC10和CArray dumb T*@liorda当前数据存储方法的限制。你不必使用std::array,你也可以使用任何其他容器,或者标准数组和std::fill,如果你想要堆栈上的内存,甚至只是在数组上循环。关键是memset可能不是答案。@user657267也很正确;从默认构造的xvalue移动应该具有与重置一样好的性能。当然,除非“重置”执行的操作不是将对象恢复到其默认状态,例如,执行对象重置次数计数器!可能是真的;但是他想调用成员函数。为非POD重置,所以他的问题remains@MattMcNabb也许吧,虽然我认为一旦你不再需要区分POD和非POD,假设他想将包含的数据重置为默认状态,那么问题就消失了,也就是说,他应该为更复杂的类提供默认构造函数,而不是重置函数。这是c++11的一个惊人特性。太糟糕了,我受到VC10和CArray dumb T*@liorda当前数据存储方法的限制。你不必使用std::array,你也可以使用任何其他容器,或者标准数组和std::fill,如果你想要堆栈上的内存,甚至只是在数组上循环。关键是memset可能不是答案。@user657267也很正确;从默认构造的xvalue开始移动
具有重置所需的良好性能。当然,除非“重置”执行的操作不是将对象恢复到其默认状态,例如,执行对象重置次数计数器!您的代码中有两个void MemberReset member函数。在上,抱歉。它们看起来太像我了。你的代码中有两个void MemberReset member函数。On,抱歉。他们看起来太像我了。