3

can I prevent the generation of a function of a templated class if the template arguments does not meet a criteria (certain value or type)? Can this be achieved by using c++ code and no preprocessor directives?

This kind of function should neither be available in the header nor in the body. This case may seem a little artificial but i did not find a solution yet.

Example class (simplified - no constructor etc.):

MyClass.h

template<int Dimension, typename TPixelType = float>
    class MyClass
{
    void DoSomething();
    void DoAnotherThing(); // this function should only be available if Dimension > 2
}

MyClass.cxx

template< int Dimension, typename TPixelType> void MyClass::DoSomething()
{...}

// pseudocode: if Dimension <= 2 do not compile next function
template< int Dimension, typename TPixelType> void MyClass::DoAnotherThing() 
{
    MethodNotToBeCompiled(); // The function I don't want to be executed
}

TestMyClass.cxx

int main()
{
    auto myclass0 = MyClass<2>();
    myclass0.DoSomething(); // OK
    myclass0.DoAnotherThing(); // (wanted) error - function not available

    auto myclass1 = MyClass<3>();
    myclass1.DoSomething(); // OK
    myclass1.DoAnotherThing(); // OK
}

Is this possible in C++XX? Or is there another approach than preprocessor directives?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
KabCode
  • 766
  • 8
  • 25

3 Answers3

7
template <int Dimension, typename TPixelType> void MyClass::DoSomething()  {/*...*/}

// if Dimension <= 2 do not compile next function
template <int Dimension, typename TPixelType>
void MyClass::DoAnotherThing() 
{
    static_assert(Dimension > 2, "function not available!" );
    // ...
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
Raffallo
  • 651
  • 8
  • 19
  • How do I handle the code after the ```static_assert()```? It seems that static_assert affects the whole compilation process. I just want a sinlge function not compiling. – KabCode May 23 '19 at 09:37
  • what do you mean? when you using this function with invalid parameter (`<=2`) the compilator doesn't allow you to do it and gives you an error `function not available!`. The code after `static_assert()` should be like normal code, there is no difference. In example after `static_assert(...);` you can put: `int i = Dimension * 3;` – Raffallo May 23 '19 at 09:44
  • Does the assert prevent the compiling of this method or just the execution? I trying to figure out at what point the ```static_assert``` unfolds its functionality. – KabCode May 23 '19 at 11:36
  • @KabCode `static_assert` gives you the compile-time error, so it prevents the compiling. – Raffallo May 23 '19 at 11:52
6

In C++2a, you might use requires to "discard" method:

template<int Dimension, typename TPixelType = float>
class MyClass
{
    void DoSomething();
    void DoAnotherThing() requires (Dimension > 2);
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • How far is the implentation of C++2a? Can it be already used (with Visual compiler)? – KabCode May 23 '19 at 09:10
  • You might look at https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=vs-2019. So currently not yet supported in visual (gcc supports `requires`). – Jarod42 May 23 '19 at 09:16
  • This would be my prefered answer if i could use ```requires```. – KabCode May 23 '19 at 12:10
  • @Jarod42 is too ahead of his/her time :-) cool solution nonetheless, [happy to have tried it out](https://godbolt.org/z/s8BZ3N)! – andreee May 23 '19 at 12:17
3

General suggestion: if you have a template class, implement all in the header and avoid cpp files. All become a lot simpler.

can I prevent the generation of a function of a templated class if the template arguments does not meet a criteria (certain value or type)? Can this be achieved by using c++ code and no preprocessor directives?

Yes and yes: search for SFINAE.

In your case (C++11 and newer)

template <int Dimension, typename TPixelType = float>
class MyClass
 {
   public:
      void DoSomething ()
       { }

      template <int D = Dimension,
                typename std::enable_if<(D > 2), bool>::type = true>
      void DoAnotherThing()
       { }
 };

Now the DoAnotherThing() method is implemented only when D > 2 where D, by default is equal to Dimension.

Isn't a perfect solution because can be "hijacked" explicating the value of D

auto myclass0 = MyClass<2>();
myclass0.DoAnotherThing<5>(); // compile because D is 5

but you can prevent this problem adding the test that D is equal to Dimension

  template <int D = Dimension, // ..VVVVVVVVVVVVVVVV
            typename std::enable_if<(D == Dimension)
                                 && (D > 2), bool>::type = true>
  void DoAnotherThing()
   { }

so

auto myclass0 = MyClass<2>();
myclass0.DoAnotherThing<5>(); // doesn't compile anymore because 5 != 2
max66
  • 65,235
  • 10
  • 71
  • 111
  • This can be combined with ```if constexpr(){}``` to prevent the function call throwing compile time errors. – KabCode May 28 '19 at 07:12