3

I have a similar problem the issue described in this SO question In my case however the optional param default values is:
1. Defined in a separate C++/CLI dll.
2. Is already defined in that lib as "public static const"
When I try to use the value as a default parameter value from C# I get "must be a compile time constant".
Is there a way to share a common const value between (C++/cli) library and (C#) app?

C++/CLI lib:

namespace MyCPlusPlusCLILib {
    public ref class CPPCLIClass {
    public:
       static const double Invalid = -1;
}

C# code:

public MyMethod(double fish = MyCPlusPlusCLILib.CPPCLIClass.Invalid) { }
// C# compiler error "Must be a compile time const"

OR

const double MyConstDouble = MyCPlusPlusCLILib.CPPCLIClass.Invalid;
// C# compiler error "Must be a compile time const"
Community
  • 1
  • 1
Ricibob
  • 7,505
  • 5
  • 46
  • 65

2 Answers2

8

The const keyword in C++ declares constants that are not all that const, it can be arbitrarily cast away with a const_cast<>.

You'll need to use a C++/CLI specific keyword to declare a .NET constant, the kind whose value is stored in the metadata but doesn't also have underlying storage. Use the literal keyword:

    literal double Invalid = -1;

Which solves your problem, the C# compiler is happy with that one. Do note the iffiness of public constants. Your C# compiler will compile the value into the generated IL directly, substituting "Invalid" with the literal value. This will turn out poorly when you update your C++/CLI assembly with a bug fix that changes the literal but don't recompile the C# code. Public constants are okay for manifest constants, like Math::Pi.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • const, readonly, literal... spoiled for choice. This is indeed the solution I was looking for. Iffiness understood and accepted in this instance (C++ code is build of firmware code - not going to change in a hurry). Thanks. – Ricibob Aug 22 '13 at 14:53
  • No, you can't use `const_cast` to remove `const` from an object declared `const`. C# `const` is more akin to C++ `constexpr`. C++ `const`, used on an object (not the target type of a pointer or reference) means that the value cannot change after initialization, however that initial (and permanent) value can be computed from run-time variables. C++ `const` (again, on an object, not the target type of a handle) corresponds to immutability. – Ben Voigt Aug 22 '13 at 16:38
1

MyCPlusPlusCLILib.CPPCLIClass.Invalid is not a compile-time constant, because you could put in a different version of MyCPlusPlusCLILib, with Invalid set to a different value.

If you don't want to make the default value for the C# method an explicit -1, you could do something like this: Pick a different value for a C# default, and when you get that, substitute in the C++/CLI Invalid.

public void MyMethod(double fish = Double.NaN)
{
    if (Double.IsNaN(fish))
        fish = MyCPlusPlusCLILib.CPPCLIClass.Invalid;

    ...
}
David Yaw
  • 27,383
  • 4
  • 60
  • 93
  • So is there any solution to this. I would like to share a single Invalid value between C++/Cli and C# code - is that possible? – Ricibob Aug 22 '13 at 13:57
  • See edit. It's not possible to share the value directly, but you can use one default value to trigger use of another. – David Yaw Aug 22 '13 at 14:07
  • This is a solution +1 - and I think Im correct in thinking it doesn't suffer ifiness of Hans solution - in that if lib is updated old sharp code will still pull new lib value from lib. But in this particular case I can live with ifiness and literal is cleaner. Thanks. – Ricibob Aug 22 '13 at 14:57