15

I am assigning to a std::function<double()> a lambda expression. This snippet works

if(fn_type==exponential)
    k.*variable = [=,&k](){ return initial*exp(-k.kstep*par); };
else
    k.*variable = [=,&k](){ return initial*pow(k.kstep, par); };

whereas if I want to use the ternary operator

k.*variable = (fn_type==exponential ? [=,&k](){ return initial*exp(-k.kstep*par); } : [=,&k](){ return initial*pow(k.kstep, par); });

I get the following error:

error: no match for ternary ‘operator?:’ in <awfully long template error, because this whole thing is in a class defined in a function...>

Is this a gcc bug (I'm using 4.7.2)? Otherwise why is there this limit in the standard?

James McNellis
  • 348,265
  • 75
  • 913
  • 977
Lorenzo Pistone
  • 5,028
  • 3
  • 34
  • 65

2 Answers2

20

The second and third operands of the conditional operator must have the same type or there must be some common type to which they can both be converted that the compiler can figure out. There are only a handful of conversions that the compiler will consider.

Your two lambda expressions have different types, and there is no common type to which they can both be converted (conversions to user-defined types, like std::function<double()>, cannot be considered because there are potentially an infinite number of valid target types).

You can directly convert each of the operands to std::function<double()>:

k.*variable = fn_type==exponential
    ? std::function<double()>([=,&k](){ return initial*exp(-k.kstep*par); })
    : std::function<double()>([=,&k](){ return initial*pow(k.kstep, par); });

But really, it's cleaner with the if/else.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 2
    +1 for answer, another +1 for " it's cleaner with the if/else." – John Dibling Oct 17 '12 at 20:01
  • 1
    Here's a related case that for some reason compiles on clang and gcc but not on MSVC: https://godbolt.org/z/4YQdVA I my mind, this shouldn't compile at all because the two sides of the `:` have different types. Any idea why it compiles at all? And who's right, MSVC or clang & gcc? – Ben Oct 11 '19 at 14:38
  • 1
    @Ben Your example is one of the few cases mentioned in the answer where a conversion happens, namely both lambdas decay to function pointers that have the same type https://godbolt.org/z/WcbzhY377 – cigien Apr 20 '23 at 16:17
  • Of course! (I've learned a lot in the past 3.5 years!) – Ben Apr 20 '23 at 17:09
-2

Also faced this issue - won't compile!

'if/else' not good for me, I would like auto type deducing feature turn on.

    auto memcpy_traits = 
        [&](uint8_t* line_dst, const uint8_t* curr_src, const size_t bytes_to_copy) {
            std::memcpy(line_dst, curr_src, bytes_to_copy);
            line_dst += bytes_to_copy;
            curr_src += bytes_to_copy;
    }
    :
     [&](uint8_t* line_dst, const uint8_t* curr_src, const size_t bytes_to_copy) {
     std::memcpy(line_dst, curr_src, bytes_to_copy);
     line_dst += bytes_to_copy;
     curr_src += bytes_to_copy;
     };
StNickolay
  • 950
  • 2
  • 9
  • 21