25

The following line has the error Default argument is not allowed.

public ref class SPlayerObj{
private:

    void k(int s = 0){ //ERROR
    }
}

Why C++ has no default argument on managed types ?
I would like to know if there is a way to fix this.

Mohsen Sarkar
  • 5,910
  • 7
  • 47
  • 86
  • 3
    "C++" doesn't have managed types, "C++/CLI" does; you should update the question – Stephen Lin Mar 16 '13 at 20:32
  • 1
    The answer is likely to become something like "because". – sehe Mar 16 '13 at 20:33
  • @StephenLin I have updated title – Mohsen Sarkar Mar 16 '13 at 20:35
  • @sehe actually, at least part of the reason is because C++ default arguments are evaluated by the caller, not the callee, so they would have to be part of the metadata of the function to work from other languages...C# added default arguments and I don't remember exactly how they work there...and this is more recent than the initial development of C++/CLI anyway – Stephen Lin Mar 16 '13 at 20:35
  • @StephenLin VB.NET has had them from the beginning. It's about CLR, not any specific language. Also, there is no issue whatsoever with default arguments, since it's `ref-class` specific anyway (C++ semantics have _nothing_ to do with it), so they could just have provided the matching semantics. However, they didn't. – sehe Mar 16 '13 at 20:38
  • 1
    What happens if you change `int` to `System::Int32`? – antonijn Mar 16 '13 at 20:50
  • @sehe didn't know about VB.NET...but sure, they could have made the same syntax have different semantics between managed and unmanaged types (and there's a lot of non-obvious corner cases with C++ default argument semantics, so they would probably have had to even if CLR defaults had caller evaluation semantics) but that would have been confusing and a reason not to do it...also, the default argument would have to be something that could be evaluated by another language as well (or at least understood by its compiler) which rules out a lot of cases too – Stephen Lin Mar 16 '13 at 20:50
  • @Antonijn Intelligence idea however no that doesn't work. – Mohsen Sarkar Mar 16 '13 at 20:51
  • (C++ defaults can be arbitrary functions and they're evaluated by the caller before calling the function: in fact, the callee doesn't even know if an argument is defaulted or not...the original declaration doesn't even have to declare it as such, as long as subsequent declaration in the translation unit of the caller does.) – Stephen Lin Mar 16 '13 at 20:53
  • There are no optional parameters in C++/CLI for managed types. This might be of interest to you: http://stackoverflow.com/questions/4974237/optional-parameters-in-managed-c-cli-methods – antonijn Mar 16 '13 at 20:58
  • @StephenLin You're not telling me anything new. Also, "they could have made the same syntax have different semantics between managed and unmanaged types" ... "but that would have been confusing and a reason not to do it": this totally flies in the face of just about everything about the essence the design of C++/CLI. The point is moot. – sehe Mar 17 '13 at 02:14
  • @sehe, well, no, C++/CLI has different semantics for native and managed types, but it's almost always with different, parallel syntax. i.e. `template` vs `generic`, `*` vs `^`, `&` vs `%`. Admittedly the destructor syntax is overloaded to do two different things, but it's the exception rather than the rule. The accepted answer basically makes the same point: C++ default arguments are basically like `template`s and CLR default arguments are like `generic`s, in that the former don't exist past compile-time and the latter do... – Stephen Lin Mar 17 '13 at 06:10
  • @sehe so it's really exactly the same as the decision not to reuse the `template` keyword for `generic`s; they're superficially similar but have different semantics so reusing the same syntax without disambiguating the two would not have been appropriate. – Stephen Lin Mar 17 '13 at 06:16
  • @sehe, to be honest, the most consistent thing to do would probably have been to allow default arguments on managed types but only allow them to be used within C++/CLI using the exact same semantics as C++ default arguments, similar to how `template`s over managed types are possible but aren't understood by non-C++/CLI code, but I can see why they didn't do that. – Stephen Lin Mar 17 '13 at 06:37
  • @StephenLin I agree :) – sehe Mar 17 '13 at 11:52

3 Answers3

18

It does have optional arguments, they just don't look the same way as the C++ syntax. Optional arguments are a language interop problem. It must be implemented by the language that makes the call, it generates the code that actually uses the default argument. Which is a tricky problem in a language that was designed to make interop easy, like C++/CLI, you of course don't know what language is going to make the call. Or if it even has syntax for optional arguments. The C# language didn't until version 4 for example.

And if the language does support it, how that compiler knows what the default value is. Notable is that VB.NET and C# v4 chose different strategies, VB.NET uses an attribute, C# uses a modopt.

You can use the [DefaultParameterValue] attribute in C++/CLI. But you shouldn't, the outcome is not predictable.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
13

In addition to the precise answer from Hans Passant, the answer to the second part on how to fix this, you are able to use multiple methods with the same name to simulate the default argument case.

public ref class SPlayerObj {
  private:
    void k(int s){ // Do something useful...
    }
    void k() { // Call the other with a default value 
       k(0);
    }
}
Community
  • 1
  • 1
holroy
  • 3,047
  • 25
  • 41
5

An alternative solution is to use the [OptionalAttribute] along side a Nullable<int> typed parameter. If the parameter is not specified by the caller it will be a nullptr.

void k([OptionalAttribute]Nullable<int>^ s)
{
    if(s == nullptr)
    {
        // s was not provided
    }
    else if(s->HasValue)
    {
        // s was provided and has a value
        int theValue = s->Value;
    }
}
// call with no parameter
k();
// call with a parameter value
k(100);
Aaron Hudon
  • 5,280
  • 4
  • 53
  • 60
  • 1
    Lots of boxing going on here. By the way, you can use s->HasValue even if it is nullptr. It's much faster. – Brain2000 Dec 28 '18 at 06:01