4

I apologize for not having time enough to make a deep investigation and relying on your help instead.

Consider the simple code:

#include <iostream>

enum class PrintColour
{
    COLOUR_1        =   0,
    COLOUR_2        =   1,
};
 
void colour( auto c = PrintColour::COLOUR_1 )
{
    switch ( c )
    {
        case PrintColour::COLOUR_1:
            std::cout << "Colour 1" << std::endl;
            break;
        case PrintColour::COLOUR_2:
            std::cout << "Colour 2" << std::endl;
    }
}

int main( )
{
//  colour( ); couldn't deduce template parameter ‘auto:1’
    colour( PrintColour::COLOUR_1 );    // Fine!
}

This code exactly as it is compiles and runs without a problem. If I uncomment the colour( );, though, g++ fires the error:

auto_param.cpp: In function ‘int main()’:
auto_param.cpp:27:10: error: no matching function for call to ‘colour()’
  colour( );
          ^
auto_param.cpp:13:6: note: candidate: template<class auto:1> void colour(auto:1)
 void colour( auto c = PrintColour::COLOUR_1 )
      ^~~~~~
auto_param.cpp:13:6: note:   template argument deduction/substitution failed:
auto_param.cpp:27:10: note:   couldn't deduce template parameter ‘auto:1’
  colour( );
          ^

It is possible that I am just missing a silly point, or it is possible that I am really stupid and misunderstood the whole thing.

Should I be able to declare a function parameter as auto while still being able to give it a default value in C++11 or C++14?

I thought the given default value would be enough to let compiler deduce the parameter type...


EDIT 1:

It think I need to make my question clearer so it won't be mistaken by Is there a way to pass auto as an argument in C++?

The point here is not passing auto to a function, but having auto in conjunction with a default value for the argument, something not considered in the aforementioned question.

EDIT 2:

As clarified in comments here, C++11 does not have such a feature of passing auto as parameter, but C++14 and on (g++ 6.3.1 defaults to "gnu++14") seem to. My original question is not related to C++11, though, and my question is not whether C++11 supports auto parameters. I was relying on auto as parameter, but forgot to double check the minimum standard version for it. My apologies and I fixed that now.

g++ -std=c++11 auto_param.cpp -o auto_param
auto_param.cpp:13:14: error: use of ‘auto’ in parameter declaration only available with -std=c++14 or -std=gnu++14

I hope it to be clear the difference between my question and Is auto as a parameter in a regular function a GCC 4.9 extension?. Please tell me if not.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
j4x
  • 3,595
  • 3
  • 33
  • 64
  • Possible duplicate of [Is there a way to pass auto as an argument in C++?](http://stackoverflow.com/questions/29944985/is-there-a-way-to-pass-auto-as-an-argument-in-c) – R Sahu Apr 26 '17 at 20:14
  • 2
    *Assuming* `auto` here is just a syntactic sugar for template parameter, you cannot call this function w/o arguments, because it's parameter type cannot be deduced in this context. – Igor R. Apr 26 '17 at 20:26
  • Possible duplicate of [Is auto as a parameter in a regular function a GCC 4.9 extension?](http://stackoverflow.com/questions/25879705/is-auto-as-a-parameter-in-a-regular-function-a-gcc-4-9-extension) – cpplearner Apr 27 '17 at 00:05

2 Answers2

4

No, it is a non-deduced context.

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, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

<...>

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

Igor R.
  • 14,716
  • 2
  • 49
  • 83
  • You are talking about template argument deduction. The OP is asking about deduction for `auto`. – R Sahu Apr 26 '17 at 20:10
  • @R Sahu how does the type deduction for "auto" parameter (defined in mini-concepts TS) differ from the one for template parameters? – Igor R. Apr 26 '17 at 20:18
  • `auto` types for function parameters are not supported in C++11. It is only supported for lambda functions in C++14. There is a proposal to support it in C++17. I haven't seen that proposal. I can't tell how similar it is for template argument deduction. it's not something we can even discuss meaningfully when dealing with C++11 or C++14. – R Sahu Apr 26 '17 at 20:22
  • I really can't tell if a `template` argument is different from `auto`. @R Sahu, could you please point me any directions? – j4x Apr 26 '17 at 20:26
  • @fljx, I have not been able to track down the C++17 proposal yet. – R Sahu Apr 26 '17 at 20:31
  • 2
    as far as I know, `void foo(auto a)` is intended to be the same as `template void foo(T a)`. – bolov Apr 26 '17 at 20:33
  • I tried to find out from C++14 draft (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf) whether `auto` is really just syntactic sugar for `template` but it is not clear to me. The best I could find is "auto: placeholder for a type to be deduced" (7.1.6.2 and 7.1.6.4). Could anybody help, please? – j4x Apr 27 '17 at 14:58
  • 2
    @fljx it is [here](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4641.pdf) See 7.1.6.4: "Similarly, if a placeholder appears in a parameter type of a function declaration, the function declaration declares an abbreviated function template" – Igor R. Apr 27 '17 at 21:52
2

Should I be able to declare a function parameter as auto while still being able to give it a default value in C++11 or C++14?

I don't know if C++17 support it but, as far I know, C++11 and C++14 don't support an auto parameter for a function (C++14 support it only for lambda functions)

I thought the given default value would be enough to let compiler deduce the parameter type...

If instead of auto you accept to use a template type, you have to add the default template type also.

Something as follows

template <typename T = decltype(PrintColour::COLOUR_1)>
void colour( T c = PrintColour::COLOUR_1 )
{
    switch ( c )
    {
        case PrintColour::COLOUR_1:
            std::cout << "Colour 1" << std::endl;
            break;
        case PrintColour::COLOUR_2:
            std::cout << "Colour 2" << std::endl;
    }
}

I know: is redundant.

-- EDIT --

The OP says

I was just wondering if I couldn't make my code more readable by not repeating

More readable probably not but... if you want it not repeating... I know that macros are distilled evil but... if you really want avoid repeating...

#define noRepeat(r, n, a, b) \
r n (decltype(b) a = b)

noRepeat(void, colour, c, PrintColour::COLOUR_1)
{
    switch ( c )
    {
        case PrintColour::COLOUR_1:
            std::cout << "Colour 1" << std::endl;
            break;
        case PrintColour::COLOUR_2:
            std::cout << "Colour 2" << std::endl;
    }
}

or also (if you want make the trick on parameter basis)

#define parDef(a, b)  decltype(b) a = b

void colour ( parDef(c, PrintColour::COLOUR_1), parDef(d, 5) )
{
    switch ( c )
    {
        case PrintColour::COLOUR_1:
            std::cout << "Colour 1" << std::endl;
            break;
        case PrintColour::COLOUR_2:
            std::cout << "Colour 2" << std::endl;
    }
}
max66
  • 65,235
  • 10
  • 71
  • 111
  • Thanks @max66. I was just wondering if I couldn't make my code more readable by not repeating `( PrintColour c = PrintColour::COLOUR_1 )`. I know it didn't work, but I still want to learn why (and possibly learn another way to tidy my code as well). As from @Igor R. comment, I was considering `auto` to be "syntactic sugar". – j4x Apr 26 '17 at 20:46
  • 1
    @fljx - I see... well... if you want avoid repeating... answer improved. – max66 Apr 26 '17 at 22:07
  • Your edit is tempting... I am considering something like `#define def_deduce( p, def_value ) decltype( def_value ) p = def_value` and later `void colour( def_deduce( c, PrintColour::COLOUR_1 ) )` but, as you stated. macros are ignominious. Last note, according to g++, it seems that C++14 supports `auto` as parameter. – j4x Apr 27 '17 at 13:26
  • 1
    @fljx - g++ accept `auto` if you forget `-pedantic`; with `-pedantic` you get an error; C++14 accept `auto` for lambda functions only (as far I know) but if you try something like `auto colour = [](auto c = PrintColour::COLOUR_1) { };`, works when you call `colour( PrintColour::COLOUR_1 );` but when you call `colour();` you get an error similar to `colour( ); couldn't deduce template parameter ‘auto:1’` (both clang++ and g++). – max66 Apr 27 '17 at 15:14