C++14 lambda's default argument type deduction depending on preceding arguments

两盒软妹~` 提交于 2019-12-23 19:05:24

问题


Is this not valid as C++14?

auto f = [](auto x, auto y = std::decay_t<decltype(x)>{}) { };
f(0);

I was expecting it to be roughly equivalent to

auto f = [](int x, int y) { };
f(0, int{});

Neither GCC 6.3 nor Clang 4.0 accepted my code.

  • http://ideone.com/b7b4SK GCC
  • http://ideone.com/EyLYaL Clang

Is it related to my lack of understanding of C++ template deduction phases? Does the 1400 pages long spec actually has an explicit answer to my question?

Update

To summarize, my problem can in fact be reduced to this piece of code (free of lambda, single parameter) and it is invalid under C++14 (thanks @BaummitAugen and @NirFriedman)

template <typename T>
void f(T x = 0) { }

int main() {
    f();
}

回答1:


The compilers are correct to reject your code, it is indeed not valid C++14.

In the standard (using N4141 here) we have

For a generic lambda, the closure type has a public inline function call operator member template (14.5.2) whose template-parameter-list consists of one invented type template- parameter for each occurrence of auto in the lambda’s parameter-declaration-clause, in order of appearance.

(5.1.2/4 [expr.prim.lambda]). So your call is equivalent to a call to some

template <class T1, class T2>
auto operator() (T1 x, T2 y = std::decay_t<decltype(x)>{});

Now

If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

(14.8.2/4 [temp.deduct.type]) and

The non-deduced contexts are:
[...]
- A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.

(14.8.2/5 [temp.deduct.type]) makes your call ill-formed.




回答2:


I can't quote the spec, but I will quote cppreference which is an authoritative source and is often easier to read/follow. In particular, see http://en.cppreference.com/w/cpp/language/template_argument_deduction.

Non-deduced contexts

In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction...

You probably are already aware that template parameters cannot always be deduced. Going down the list of entries, we see:

4) A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done:

Which gives the following example:

template<typename T, typename F>
void f(const std::vector<T>& v, const F& comp = std::less<T>());
std::vector<std::string> v(3);
f(v);

variadic lambdas are basically equivalent to function templates with a type template parameter substituted for each usage of auto, so this example (which does not compile) is equivalent to your example.

So basically, the second type cannot be deduced because it is a non-deduced context.

This answer could probably be improved by giving a very good example of why exactly it's been decided to make this a non-deduced context, since naively it seems like it's possible. My guess is that this is basically because a function template is just that, a template for creating function. Defaulted arguments in turn, essentially create multiple callable signatures for the same function. So you can't really deal with defaulting, until you have a function, but you can't have a function until you instantiate, which requires knowing the template parameters.

It's instructive to note that this simpler example has the same issues:

template<typename T, typename F>
void f(const std::vector<T>& v, const F& comp = int{});

So the dependence on the first template parameter actually has nothing to do with the issue.



来源:https://stackoverflow.com/questions/42240849/c14-lambdas-default-argument-type-deduction-depending-on-preceding-arguments

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!