3

Is there any way I can emulate C++ value template parameters in C#?

template<bool flag>
void Method()
{
     // Do some work
     if constexpr(flag)
     {
          // Do something specific
     }
     // Do some more work
}

So that it would generate two versions of a method which can be called like this:

Method<false>();
Method<true>();

This is for performance reasons, so it is better to not make additional calls inside the Method. The Method is performance critical part and it is called billions of times so it is important to squeeze every CPU cycle from it.

On the other hand it has a rather complicated logic, so I would prefer to not have two copies of it.

I think I could do something with generics, but it wouldn't be the best option for performance. So now the only way I can think of is to create some kind of template code generator for it. But maybe there are other options? Maybe it is possible to compile two versions of the method using Roslyn, so that it would create two optimized versions of it with specific arguments?

void Method(bool flag)
{
     // Do some work
     if (flag)
     {
          // Do something specific
     }
     // Do some more work
}

So that I can compile it to:

void Method_false(false)
{
     // Do some work
     // Do some more work
}

and to:

void Method_true(true)
{
     // Do some work
     // Do something specific
     // Do some more work
}

Is it at all possible?

Max
  • 19,654
  • 13
  • 84
  • 122
  • I doubt this is possibe, and even if it were, you´d have to indicate which of those two methods you want to call at some point. At some point you **have** to perform the switch somehow. However if the client-code is just called once, that´s no big issue. – MakePeaceGreatAgain Apr 15 '19 at 19:43

2 Answers2

2

Metaprogramming is not possible in C#. Look for possible alternatives in the form of code transformation tools in the following SO question: Is metaprogramming possible in C#?

Elvir Crncevic
  • 525
  • 3
  • 17
1

You can't do this from language directly, however it is possible because JIT is smart enough. Create an interface and two structs:

public interface IBool
{
    bool IsTrue();
}

public struct True : IBool
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool IsTrue()
    {
        return true;
    }
}

public struct False : IBool
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool IsTrue()
    {
        return false;
    }
}

Please note that implementations of IsTrue are marked with MethodImpl attribute. Now rewrite your Method as generic:

public static void Method<T>(ref T flag) where T : struct, IBool
{
    if (flag.IsTrue())
    {
        Console.WriteLine(42);
    }
    else
    {
        Console.WriteLine(24);
    }
}

There is important thing: T has struct constraint so JIT aware that there is no inherited types from T and nobody can override return value of IsTrue. Also, because this method will be inlined, JIT replace call to IsTrue with constant. And when you have

if (false)
{
    // some code
}

that means that whole code block will be removed. As a result JIT will create two implementations of Method: first with content of if section and seconf with content of else section. You can check this in disassembly window:

Two calls with different target address

Aleks Andreev
  • 7,016
  • 8
  • 29
  • 37