包装模板功能和

时间:2013-12-28 00:29:47

标签: c++ function templates overloading wrapper

我的包装功能有问题。

template <typename Iter, typename SomeFunction>                         
void wrap(Iter first, Iter last, SomeFunction someFunction)
{
  someFunction(first, last);
}

我想像这样使用它:

template <typename Iter>
void fill5(Iter first, Iter last)
{
    fill(first, last, 5); 
}
int main()
{
    vector<int> v(100, -1);
    wrap(v.begin(), v.end(), fill5);

}

但是我得到了

test.cpp: In function ‘int main()’:
test.cpp:16:40: error: no matching function for call to ‘wrap(std::vector<int>::iterator, std::vector<int>::iterator, <unresolved overloaded function type>)’
test.cpp:16:40: note: candidate is:
wrap.h:6:6: note: template<class Iter, class SomeFunction> void wrap(Iter, Iter, someFunction)

我知道如果我将这样的功能称为

wrap(v.begin(), v.end(), fill5< vector<int>::iterator> );

它会编译。但我是否总是要明确这样做?太糟糕了。为什么编译器无法推断出将使用哪个函数?是否有可能编写wrap函数来获取第一个参数?

3 个答案:

答案 0 :(得分:8)

在C ++ 03或C ++ 11中,你无能为力。

fill5是一个函数模板,您无法获取函数模板的地址。编译器将函数模板视为无限重载集,并要求您明确指定要使用以下地址的实例:

wrap(v.begin(), v.end(), fill5<vector<int>::iterator>);
//                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

或者(正如我在原始帖子的评论中提到的,以及其他答案建议),您可以使用带有模板化调用运算符的仿函数来包装fill5的调用。

然而,在C ++ 14中,我们可以做得更好:我们可以使用通用lambdas来简化一些事情。如果您定义此宏:

#define WRAP(f) \
    [&] (auto&&... args) -> decltype(auto) \
    { return f (std::forward<decltype(args)>(args)...); }

然后你可以写:

int main()
{
    std::vector<int> v(100, -1);
    wrap(v.begin(), v.end(), WRAP(fill5));
}

这是live example

答案 1 :(得分:3)

另一种方法是使用仿函数:

class fill5
{
public:
    template <typename Iter>
    void operator () (Iter first, Iter last) const
    {
        std::fill(first, last, 5); 
    }
};

int main( int, char ** )
{
    std::vector<int> v(100, -1);

    wrap(v.begin(), v.end(), fill5);
    return 0;
}

答案 2 :(得分:1)

因为fill是一个模板函数,基本上有无限数量的重载,编译器不知道选择哪一个。

如果你声明你的第二个模板参数来描述一个带有2个Iter类型参数的函数,那么它就可以推导出它。以下示例有效,看起来就像您想要的那样。它并不像你的尝试那样通用。它确保被调用的函数返回void并且需要2个Iter参数。

template <typename Iter >
void wrap( Iter first, Iter last, void(*someFunction)(Iter,Iter) )
{
someFunction( first, last );
}

template <typename Iter>
void fill5(Iter first, Iter last)
{
    fill(first, last, 5); 
}

int main( int, char ** )
{
std::vector<int> v(100, -1);
wrap(v.begin(), v.end(), fill5);

return( 0 );
}