4

With dynamic polymorphism I can create interface, that cannot be instantiated, because some methods are pure virtual.

What is the equivalent with static polymorphism?

Consider this example:

template<typename T> string f() { return ""; }
template<> string f<int>() { return "int"; }
template<> string f<float>() { return "float"; }

I want to "disable" the first one, similarly as when I declare a method of a class to be pure virtual.

Ruggero Turra
  • 16,929
  • 16
  • 85
  • 141
  • Have you considered using `static_assert`? – Captain Obvlious Mar 13 '15 at 17:33
  • CRTP? https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern – Luka Rahne Mar 13 '15 at 17:34
  • @CaptainObvlious: can you elaborate? `static_assert(false, "dont")` always assert – Ruggero Turra Mar 13 '15 at 17:35
  • In combination with CRTP, you can do an interface check for `T` to if the needed operations are available at compile time and let the compiler bail out early, and not only when these functions are instantiated. Usually you define a set of function pointers for the required methods, and try to initialize a (not further used) variable with these function addresses. – πάντα ῥεῖ Mar 13 '15 at 17:37
  • Perhaps template constraints or concepts. See for example http://stackoverflow.com/questions/15669592/what-are-the-differences-between-concepts-and-template-constraints – sfjac Mar 13 '15 at 17:38
  • 1
    @RuggeroTurra: make the condition dependant on the template to work around that. `static_assert(sizeof(T)==0, "dont")` – Mooing Duck Mar 13 '15 at 18:39

1 Answers1

9

Question:

What is the equivalent with static polymorphism?

Declare a function template without an implementation. Create implementations only for the types that you want to support.

// Only the declaration.
template<typename T> string f();

// Implement for float.    
template<> string f<float>() { return "float"; }

f<int>();   // Error.
f<float>(); // OK

Update

Use of static_assert:

#include <string>

using std::string;

template<typename T> string f() { static_assert((sizeof(T) == 0), "Not implemented"); return "";}

// Implement for float.    
template<> string f<float>() { return "float"; }

int main()
{
   f<int>();   // Error.
   f<float>(); // OK
   return 0;
}

Compiler report:

g++ -std=c++11 -Wall    socc.cc   -o socc
socc.cc: In function ‘std::string f()’:
socc.cc:6:35: error: static assertion failed: Not implemented
<builtin>: recipe for target `socc' failed
Ruggero Turra
  • 16,929
  • 16
  • 85
  • 141
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • I think this directly answers the question and I agree with @CaptainObvious that using `static_assert` is useful for providing a _nicer_ error message. – James Adkison Mar 13 '15 at 17:50
  • @JamesAdkison: can you elaborate on `static_assert`? how to use here? – Ruggero Turra Mar 13 '15 at 18:24
  • @RuggeroTurra, with my suggestion, there is no need for using `static_assert`. The compiler will generate an error if the function is not implemented for a given type. – R Sahu Mar 13 '15 at 18:27
  • @RSahu: yes, I see. But still I don't undestand how to use the option with `static_assert`. `template string f() { static_assert(false, "dont"); }` do not work. – Ruggero Turra Mar 13 '15 at 18:29
  • @RuggeroTurra I believe you have the right idea, regarding your comment to @CaptainObvious. You could do `std::static_assert(false, "The f() function was instantiated with an unsupported type, use a different overload")`. While this is not necessary without it I get an **linker error** `error LNK2019: unresolved external symbol "class std::basic_string ....` (I truncated the error b/c it's rather long). But `static_asset` would produce a **compiler error** with the specified message, `error C2338: The f() function was instantiated with an unsupported type, use a different overload`. – James Adkison Mar 13 '15 at 18:33
  • 2
    @RSahu I think that `static_assert` always triggers. Usually what I see is `static_assert(sizeof(T)==0, `, which makes it dependent. – Mooing Duck Mar 13 '15 at 18:38
  • could someone elaborate on that `sizeof` trick? what's `T` in that case? – Karoly Horvath Mar 13 '15 at 18:52
  • @KarolyHorvath: `T` is whatever the template parameter of `f` is. If one writes `f()` then `T=int`, and the compiler checks if `sizeof(int)==0`. It's not, so it asserts. But the compiler can't check ahead of time because `T` isn't known ahead of time. – Mooing Duck Mar 13 '15 at 18:56
  • Got it... so you could have any silly expression there that evaluates to false as long as it "depends" on `T`. This looks like the shortest and cleanest one though. Nice. – Karoly Horvath Mar 13 '15 at 19:14