Why C++ CLI has no default argument on managed types?
Asked Answered
W

3

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.

Warfeld answered 16/3, 2013 at 20:31 Comment(15)
"C++" doesn't have managed types, "C++/CLI" does; you should update the questionEmulsifier
The answer is likely to become something like "because".Lussi
@StephenLin I have updated titleWarfeld
@Lussi 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 anywayEmulsifier
@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.Lussi
What happens if you change int to System::Int32?Recessional
@Lussi 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 tooEmulsifier
@Antonijn Intelligence idea however no that doesn't work.Warfeld
(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.)Emulsifier
There are no optional parameters in C++/CLI for managed types. This might be of interest to you: #4974737Recessional
@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.Lussi
@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 templates and CLR default arguments are like generics, in that the former don't exist past compile-time and the latter do...Emulsifier
@Lussi so it's really exactly the same as the decision not to reuse the template keyword for generics; they're superficially similar but have different semantics so reusing the same syntax without disambiguating the two would not have been appropriate.Emulsifier
@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 templates over managed types are possible but aren't understood by non-C++/CLI code, but I can see why they didn't do that.Emulsifier
@StephenLin I agree :)Lussi
S
17

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.

Sibling answered 16/3, 2013 at 23:3 Comment(2)
Do you know if [DefaultParameterValue] has fixed in VS2012 ?Warfeld
C++/CLI hasn't changed since VS2005.Sibling
B
12

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);
    }
}
Bethought answered 7/1, 2015 at 10:38 Comment(1)
So, it's as crappy as Java!Puckett
G
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);
Glindaglinka answered 30/3, 2017 at 19:49 Comment(1)
Lots of boxing going on here. By the way, you can use s->HasValue even if it is nullptr. It's much faster.Puckett

© 2022 - 2024 — McMap. All rights reserved.