继续使用continual monad元组。怎么了?

时间:2014-08-27 17:45:14

标签: c++ templates tuples monads c++14

关注tuple continuation monad,假设我定义了一个仿函数std_tuple,从monad-tuple的导管到std::tuple

auto std_tuple = [](auto... args)
{
    return [=](auto f){ return f(std::make_tuple(args...)); };
};

现在我们可以在期望std::tuple的上下文中使用monad-tuples:

template<typename... ARGS>
void f( const std::tuple<ARGS...>& t ){}

int main()
{
    tuple(1,2,3)(std_tuple)(f);
}

到目前为止一切顺利。除了这不编译。 Clang 3.4.1抱怨:

  

注意:候选模板被忽略:无法推断模板参数'$ auto-1-0'

f(t)仿函数内的std_tuple来电。

这是正确的,是不是那些模板argumments可以推断?如果是肯定的,为什么?

1 个答案:

答案 0 :(得分:4)

重现问题的简单案例:

void f(int) {}
void f(double) {}

template<class T> void call_with_3( T t ) { t(3); }

int main() {
  call_with_3( f );
}

在这里,我们可以看到在我们将f传递给call_with_3时无法确定哪个f。现在,你似乎没有多次重载(你只有一个template!),但......

template不是实例。 template函数是函数的工厂,而不是函数。

没有任何对象或价值可以传播。

当您将函数名称作为参数传递时,重载决策将启动。如果目标类型已知(作为函数引用或指针),则用于对函数名称执行重载解析。

在这种情况下,您将函数名称传递给autostatic struct f_overload_set_t { template<class... Args> auto operator()(Args&&... args) const { return f(std::forward<Args>(args)...); } } f_overload_set; 参数),因此没有可以完成的重载决策,因此找不到特定的值,所以你得到一个错误。

您可以创建一个对象,其效果是对具有给定函数名称的调用参数执行重载解析。我称之为过载集对象。

->decltype( f( std::declval<Args>()... ) )

在C ++ 11中,const之后需要f_overload_set(blah)

现在f(blah)将会(几乎)执行f_overload_set时发生的事情#define OVERLOAD_SET( FUNC )\ ([](auto&&... args){\ return FUNC(std::forward<decltype(args)>(args)...);\ }) ,但FUNC是实际对象。所以你可以传递它。

生成此类重载集的宏相对容易编写。他们也可以使用lambdas,因为如果你想的话,上面就像一个无状态的lambda。

基于无状态lambda的宏重载集生成器的优点在于它可以在使用点创建。来自@ dyp上面的评论:

operator[]

(注意:[[周围没有括号,因为它阻止了ADL)。围绕其他一切的括号,因为否则如果在下标操作(template<typename... ARGS> void f( const std::tuple<ARGS...>& t ){} int main() { tuple(1,2,3)(std_tuple)(OVERLOAD_SET(f)); } )中使用,它将被解析为{{1}}启动属性,以及其他点(感谢@ecatmur))

使您的代码成为:

{{1}}