【问题标题】:C++ Single function pointer for all template instances所有模板实例的 C++ 单函数指针
【发布时间】:2016-07-21 03:13:30
【问题描述】:

有没有一种简洁的方法来指向模板化函数的所有实例而不使用宏?

我有几个模板化的函数,我想在各种类型中进行测试:

template<typename T>
void function1() {
  return;
}

template<typename T>
void function2() {
  return;
}

template<typename T>
void function3() {
  return;
}

我可以用宏来做到这一点:

#define TEST_ACROSS_TYPES(fn) \
fn<int>();  \
fn<bool>(); \
fn<char>(); \
fn<double>(); \

TEST_ACROSS_TYPES(function1);
TEST_ACROSS_TYPES(function2);

但是,(1) 宏很难看,其他人难以理解,(2) 我使用的是CATCH,在使用宏设置测试用例时效果不佳。

有没有办法做这样的事情:

void testAcrossTypes(SomeType f) {
  f<int> ();
  f<bool> ();
  f<char> ();
  f<double> ();
}

这似乎更干净,除了定义SomeType 的问题。这个问题 (How to define typedef of function pointer which has template arguments) 解释了如何定义一个指向模板函数的指针;但是,需要指定模板参数。


为了澄清:假设function1function2function3 分别测试不同的模板函数。每个函数都需要针对intbytechardouble 等进行测试。我想避免为每个函数显式设置许多(即 num_functions * num_types)测试。相反,我希望有一个方法指向测试函数(function1function2 等)并针对每种模板类型运行它,从而合并

function1<int>();
function1<byte>();
function1<char>();
function1<double();
...
function2<int>();
function2<byte>();
function2<char>();
function2<double();
...
function3<int>();
function3<byte>();
function3<char>();
function3<double();
...

每个测试函数只调用一次

testAcrossTypes(function1);
testAcrossTypes(function2);
testAcrossTypes(function3);

【问题讨论】:

  • XY 问题?我不明白你在追求什么。
  • 我正在尝试解决这个问题:stackoverflow.com/questions/38491608/…。具体来说,我正在尝试用纯代码替换宏。该示例剥离了测试细节。想象一下function1 测试一个模板函数。
  • 实际运行什么

标签: c++ templates macros function-pointers


【解决方案1】:

你想要完成的事情

void testAcrossTypes(SomeType f) {
  f<int> ();
  f<bool> ();
  f<char> ();
  f<double> ();
}

如果SomeType 可以是模板模板参数,则可能。但是,标准不允许函数模板作为模板模板参数。

来自 C++11 标准:

14.3.3 模板模板参数

1 模板模板参数的模板参数应该是类模板或别名模板的名称,表示为id-expression。

您最好的选择是使用仿函数而不是函数。示例:

template<typename T>
struct function1
{
   void operator()() {
      return;
   }
};

template<typename T>
struct function2
{
   void operator()() {
      return;
   }
};

template < template <typename> class F>
void testAcrossTypes() {
  F<int>()();
  F<bool>()();
  F<char>()();
  F<double>()();
}

int main()
{
   testAcrossTypes<function1>();
   testAcrossTypes<function2>();
}

【讨论】:

    【解决方案2】:

    您可以通过类型擦除函子来完成它,例如以下示例中的函子:

    #include<vector>
    
    template<typename T>
    void function1() { }
    
    template<typename T>
    void function2() { }
    
    template<typename T>
    void function3() { }
    
    struct Test {
        template<typename T>
        static void proto() {
            function1<T>();
            function2<T>();
            function3<T>();
        }
    
        void operator()() {
            for(auto &f: vec) f();
        }
    
        template<typename... T>
        static Test create() {
            Test test;
            int arr[] = { (test.vec.emplace_back(&proto<T>), 0)... };
            (void)arr;
            return test;
        }
    
        using func = void(*)(void);
        std::vector<func> vec;
    };
    
    void testAcrossTypes(Test test) {
        test();
    }
    
    int main() {
        testAcrossTypes(Test::create<int, bool, char, double>());
    }
    

    这两种情况都很容易修改:

    • 需要将新函数添加到proto 静态成员方法中,仅此而已

    • 添加新类型是调用create时使用的问题,如上例所示

    仿函数将继续负责创建要执行的 N*M 个调用。
    此外,您无需将函数移动到一堆结构中即可使用它们。

    【讨论】:

    • 非常有趣。您能否详细解释一下这部分:(test.vec.emplace_back(&amp;proto&lt;T&gt;), 0)...(尤其是...)?
    • @Zack 省略号解包参数包T。解决折叠表达式即将到来的事实是一个技巧。究竟有什么疑问?
    • 这是我多年以来的第一个 C++ 项目。我以前没见过这种语法,也不知道叫什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-18
    • 2019-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多