类型扣除不起作用

时间:2016-10-17 12:34:07

标签: c++ templates type-deduction

我有以下问题。当我尝试编译以下代码时

template< typename T >
T func( T t)
{
  return t;
}

template< size_t N, typename T >
void foo( std::function< T(T) > func )
{
  // ...
}

int main()
{
  foo<3>( func<float> );

  return 0;
}

我收到错误:

 no matching function for call to 'foo'
      foo<3>( func<float> );
      ^~~~~~
/Users/arirasch/WWU/dev/xcode/tests/tests/main.cpp:18:10: note: candidate template ignored: could not match 'function<type-parameter-0-1 (type-parameter-0-1)>' against 'float (*)(float)'
    void foo( std::function< T(T) > func )

然而,当我将其修复为

template< typename T >
T func( T t)
{
  return t;
}

template< size_t N, typename T >
void foo( std::function< T(T) > func )
{
  // ...
}

int main()
{

  std::function< float(float) > input_func = func<float>;
  foo<3>( input_func );

  return 0;
}

即,当我将foo的输入函数明确声明为std::function< float(float) >时,编译可以成功完成。

有没有人知道如何修改我的代码,以便我可以简单地写一些像foo<3>( func<float> );(根据我的第一个代码示例)而不是

std::function< float(float) > input_func = func<float>;
foo<3>( input_func );

哪里必须明确说明input_func的类型?

非常感谢提前。

3 个答案:

答案 0 :(得分:4)

这里的问题是编译器必须执行重载解析以找出哪些std::function<U(U)>实例具有可以采用T(*)(T)的构造函数。也就是说,可能存在多种类型,每种类型可能有多个ctors可能会占用您的input_func

现在,如果您查看标准版,您会发现没有为std::function指定此类重载,但所有模板的重载决策规则是相同的,无论它们来自{{1 },std::boost::。编译器不会开始实例化模板以查找转换序列。

一旦提供完美匹配,就不需要转换序列。只有一种目标类型不需要转换序列,编译器推断出这种类型。

在这种特殊情况下,您了解函数指针与ACME::之间的关系,以及您必须具有返回相同类型(无std::function)的单一函数的特定限制,以便你可以添加一个重载

T(*)(U)

答案 1 :(得分:3)

类型扣除在您的情况下不起作用仅仅因为它无法推断。在大多数情况下,类型推导是与类型和其他模板参数的简单匹配。然而,有一些C ++的黑暗角落处理具有一些时髦规则的演绎,但我不会因为这个答案而进入演绎。

这是编译器可以推导出模板参数的示例:

template<typename T>
void test(std::vector<T>);

test(std::vector<int>{1, 2, 3, 4, 5, 6});

这对编译器来说很容易。它需要一个T的向量。你给它一个整数向量。 T必须是int。

然而,在你的情况下,还有很多事情发生了:

template<typename T>
void test(std::function<T(T)>);

int someFunc(int);

test(someFunc);

编译器无法进行匹配。亲自尝试:给我一个T,使这两种类型相等:int(*)(int)std::function<T(T)>。实际上,没有可能T可以使这两种类型相同,而矢量版本很容易匹配。

你会对我说:&#34;但是...指向函数的指针可以转换成std :: function你傻了!&#34;是的,它确实是敞篷车。但在进行任何转换之前,编译器来查找T。没有T,你可以从指向函数的指针转换成什么类?很多课?尝试匹配每个T?您的功能可以转换为多种可能性。

你怎么能做这个工作?忘记std::function。只需收到T

template<typename T>
T func(T t) {
  return t;
}

template<size_t N, typename T>
void foo(T func) {
  // ...
}

int main()
{
  foo<3>( func<float> );

  return 0;
}

注意这个例子如何运作良好。你没有转换,没有std::function的东西,可以使用你可能想象的任何可调用对象!

您是否担心接受任何类型?别担心!无论如何,参数类型是表达模板对接收参数可以做什么的不好方法。您应该使用表达式对其进行限制。该表达式将告诉其他人您将如何使用T以及T所需的接口。顺便说一句,我们称之为sfinae:

template<size_t N, typename T>
auto foo(T func) -> void_t<decltype(func(std::declval<int>()))> {
  // ...
}

在此示例中,您可以使用func限制int可调用。

如果您还没有C ++ 17编译器,可以像这样实现void_t

template<typename...>
using void_t = void;

答案 2 :(得分:2)

将func强制转换为std :: function可以明确解决问题。例如。以下代码有效。

template< typename T >
T func( T t)
{
  return t;
}

template<typename T>
using FuncType = std::function<T(T)>;

template< size_t N, typename T >
void foo( FuncType<T> func )
{
  // ...
}

int main()
{
  func<float>(1.0);
  foo<3>( FuncType<float>(func<float>) );

  return 0;
}