Templates 使用std::function作为模板参数+;非模板函数重载

Templates 使用std::function作为模板参数+;非模板函数重载,templates,c++11,overloading,Templates,C++11,Overloading,问题就在这里。论坛主题底部的代码只是一个最简单的例子,我认为这是在基于参数类型的重载函数推导的情况下重现的编译器错误。 有一个功能: void f(const T& v, const std::function< bool( const T& ) >& validator ); void f(const bool& v); f( 5, false ); 更准确地说,应该禁用函数模板生成以bool为值的函数: template<bool>

问题就在这里。论坛主题底部的代码只是一个最简单的例子,我认为这是在基于参数类型的重载函数推导的情况下重现的编译器错误。 有一个功能:

void f(const T& v, const std::function< bool( const T& ) >& validator );
void f(const bool& v);
f( 5, false );
更准确地说,应该禁用函数模板生成以bool为值的函数:

template<bool>
void f(const bool& v, const std::function< bool(const bool&) >& validator) = delete;
。。。将发出C2660错误,告知“f”不接受2个参数,或者没有这样的重载版本接受那么多参数。当然,这是一个彻头彻尾的谎言,也是一个编译器错误。 现在,评论这句话:

#define USE_FUNCTOR
。。。因此,启用带有函数指针参数的“f”版本作为验证器而不是函子。然后代码编译得非常好。如果希望将函数指针参数替换为普通布尔参数:

template< typename T >
void f(const T& v, const bool isValid )
{
    if (isValid)
    {
        std::cout << v;
    }
}
不会再有任何编译器错误了。 显式修复:通过显式指定模板参数类型调用f的模板版本: 台词:

f(5, [](const int& a){ return a != 0; });
f(5, & isIntValid );
。。。应成为:

f<int>(5, [](const int& a){ return a != 0; });
f<int>(5, & isIntValid );
f(5,[](const int&a){返回a!=0;});
f(5,&无效);
但是,很明显,对于所有的“f”重载,这种区分用法并不统一。 请注意,当使用非模板代码时,不会再现该错误:

void b(const int a, const std::function< bool(const int& v) >& validator)
{
    if (validator(a))
    {
        std::cout << a;
    }
}

void b(const int a)
{
    std::cout << a;
}

// ...
b(5, [](const int& a){ return a != 0; });
b(5);
void b(常量int a,常量std::function&验证器)
{
if(验证器(a))
{
标准::cout和validator)
{
if(验证器(v))
{
标准::cout
无效f(持续T&v,bool(*验证者)(持续T&a))
{
如果((*验证人)(v))
{

std::cout尽管Microsoft编译器给出了一个相当误导性的错误,但拒绝您的代码是正确的

由于lambda或函数指针不能用于推断
std::function
的模板参数,因此不会选择双参数版本

我建议将函数类型设置为模板参数:

template< typename T, typename F >
void f(const T& v, F validator )
{
    if (validator(v))
    {
        std::cout << v;
    }
}
模板
无效f(常数T&v,f验证器)
{
if(验证器(v))
{
标准::cout和validator)
main.cpp:7:6:注意:已忽略候选模板:无法将“函数”与“bool(*)(const int&)”匹配
无效f(常数T&v,常数标准::函数&验证器)

问题在于
T
在参数
v
和参数
验证器
中都处于推导上下文中,这意味着调用方必须提供实际的
std::function
对象才能进行推导。lambda不是
std::function
类型

由于您只需要对第一个参数进行推断,因此您需要一个帮助器来使第二个
T
出现不进行推断:

template <class T>
struct NonDeduced
{
  typedef T type;
};

template <class T>
void f(const T& v, const std::function< bool( const typename NonDeduced<T>::type& ) >& validator );
模板
非导出结构
{
T型;
};
模板
void f(const T&v,const std::function&验证器);


作为旁注,您草拟的“已删除专业”的语法不正确。可能是:

template<>
void f(const bool& v, const std::function< bool(const bool&) >& validator) = delete;
模板
void f(const bool&v,const std::function&validator)=删除;

以前版本的代码与您的代码完全相同,但std::function代码的目标是防止用户提供错误的验证器:char*b(const int&v);因此,这是一个完全有效的验证器。返回值将隐式转换为bool。限制可能的验证器类型也会减少编译器生成的函数。“由于lambda或函数指针不能用于推断std::function的模板参数,因此不会选择双参数版本。"标准是否明确规定了它?在MSVS2013中使用
template
,并观察结果。以前它是
template
,但不使用MSVS2013。@Ivan
template
定义了一个新模板,而不是您拥有的模板的专门化。如果MSVC对此代码有问题,请尝试显式参数:
template voidf(
我可能应该读更多。因此,作为本主题的一个附带问题,如何(以及为什么)人们实际上会使用
template
作为模板吗?@Ivan恐怕这个问题太宽泛了。当你需要通过编译时
bool
进行参数化时就可以了。看看
std::enable\u if
std::conditional
的例子(它们是类,不是函数)。
main.cpp:7:6: note: candidate template ignored: could not match 'function<bool (const type-parameter-0-0 &)>' against '(lambda at main.cpp:38:10)'
void f(const T& v, const std::function< bool( const T& ) >& validator )

main.cpp:7:6: note: candidate template ignored: could not match 'function<bool (const type-parameter-0-0 &)>' against 'bool (*)(const int &)'
void f(const T& v, const std::function< bool( const T& ) >& validator )
template <class T>
struct NonDeduced
{
  typedef T type;
};

template <class T>
void f(const T& v, const std::function< bool( const typename NonDeduced<T>::type& ) >& validator );
template<>
void f(const bool& v, const std::function< bool(const bool&) >& validator) = delete;