当前位置:  开发笔记 > 编程语言 > 正文

C++使用可变参数模板编译时间特定的函数

如何解决《C++使用可变参数模板编译时间特定的函数》经验,为你挑选了1个好方法。

我目前正在开发一个用于函数抽象的库.我想将一个多参数函数抽象为一个参数函数,它是一个索引.我可以选择传递一个谓词对象,该对象确定它是否应该运行代码.

using FnType = std::function;

template
const FnType make_fn(const Fn &fn, const Predicate &predicate, Args ... args) {
    return [&](const unsigned long idx) {
        if(predicate(idx)) fn(idx, args ...);
    };
}

template
const FnType make_fn(const Fn &fn, Args ... args) {
    return [&](const unsigned long idx) {
        fn(idx, args ...);
    };
}

使用谓词时,此代码可以正常工作.

std::vector data(10);
auto fn = [&](unsigned idx, double d) { data[idx] *= d; };
auto pred = [](unsigned long idx) { return idx % 2 == 0; };
FnType new_fn = make_fn(fn, pred, 2.0);

但是当我试图传递没有谓词时

FnType new_fn2 = make_fn(fn, 2.0);

它返回以下编译时错误消息:

called object type 'double' is not a function or function pointer
    if(predicate(idx)) fn(idx, args ...);
       ^~~~~~~~~

是否有可能说编译器应该使用不使用任何谓词的第二个函数?



1> Barry..:

我们来看看你的签名:

template
const FnType make_fn(const Fn&, const Predicate&, Args ...); // (1)

template
const FnType make_fn(const Fn&, Args ... ) // (2)

当我们打电话时:

make_fn(fn, 2.0);

没有什么特别的Predicate- 它只是另一种类型.因此,当我们执行重载决策时,我们有两个完全匹配.我们解决可变参数的方式(1)是比它更专业(2)- 因为(1)至少需要2个参数并(2)至少需要1个参数,前者更具体.这就是我们称之为前者的原因.编译器不会从签名中知道您的意思Predicate.

最简单的解决方案是简单地重命名一个函数或另一个函数 - 你真的需要它们重载吗?有一个make_fn()和一个make_predicate_fn().

或者,我们可以通过强制执行可更改改变SFINAE Predicate:

template ()(0u))>
const FnType make_fn(const Fn&, const Predicate&, Args ...);

那会使(1)你的电话形成不良,所以(2)会更受欢迎.虽然如果你不想以这种方式使用谓词,但另外还有一些函数,其第一个参数是谓词,那么这又有一个缺点.会发生错误的事情.

TC在评论中提出的更好的解决方案是引入一个空标签类型:

struct predicate_tag_t { };
constexpr predicate_tag_t predicate_tag{}; 

并且存在该标记时出现过载:

template 
FnType make_fn(const Fn&, predicate_tag_t, const Predicate&, Args&&... );

template 
FnType make_fn(const Fn&, Args&&... );

那样你的例子变成了:

FnType new_fn = make_fn(fn, predicate_tag, pred, 2.0);
FnType new_fn2 = make_fn(fn, 2.0);

make_fn当你有:时,你有两个s中的悬空引用:

const FnType make_fn(const Fn &fn, Args ... args) {
    return [&](const unsigned long idx) { ... }
}

您正在复制所有的args,然后保留对所有args的引用.但是一旦make_fn完成,所有的args都超出了范围.你需要复制它们 - 所以[=].

推荐阅读
黄晓敏3023
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有