5

I’m looking for information on a pattern that I have used recently. The basic idea is that there is a type with a property that can either be compile-time (template parameter) or runtime (member). std::span is a good example of this pattern. Here is an example of the pattern in its purest form:

// sentinel value
constexpr int runtime = -1;

// compile-time version
template <int Property = runtime>
struct Type {
  static constexpr int getProp() {
    return Property;
  }
};

// runtime version
template <>
struct Type<runtime> {
  int getProp() const {
    return property;
  }
private:
  int property;
};

template <typename T>
int square(T obj) {
  // does a multiply if T is Type<runtime>
  // otherwise returns a constant
  return obj.getProp() * obj.getProp();
}

You usually end up with two very similar classes so I typically hoist common code up into a base class using the CRTP idiom.

  • Does this pattern have a name?
  • If there isn’t a good name, how should I describe it? (The title of the question is my best attempt)
  • Has someone written about this pattern somewhere?
  • When should I avoid using this pattern?
1

OK, I'll be only referring to 'When should I avoid using this pattern?':

I tend to say 'always':

  1. There's a sentinel value (in given case -1) – what if you need it at compile time? Then you'd still have to use the runtime variant.
  2. Any two of Type<n> with differing values for n are different, independent types. So if you intended to use them together in a container – bad luck. But if you cannot, then what's use case for?

So instead of specialising one special (sentinel) value, I'd go with two totally unrelated classes:

template <int Property>
struct CompileTimeType
{
    static constexpr int getProp() { return Property; }
};
struct RunTimeType
{
    int getProp() const { return property; }
private:
    int property;
};

Be aware that as is now, you'd have to use both differently anyway:

CompileTimeType<whatEver>::getProp();
RuntimeType rtt;
rtt.getProp();

All no problem if you know in advance what type you have. Want to use them in template functions? Well, one time, you need an instance, the other time not. Hmm... – Still want to have an instance for compile time variant as well? Then you can make the function non-static.

If you want to combine arbitrary combinations of comtile and run time instances in a container, you'd need a common base class anyway (even for different compile time instanciations, not considering the run time variant...). Then you'd be forced to have non-static functions in all variants. But the virtual function call you introduce this way will consume up all advantages you gained previously by template usage, so you could as well stay with the runtime variant only then and likely are even better off...

  • “What if you need the sentinel at compile time”. How often do you need an array with a size of -1? – Kerndog73 Dec 19 '18 at 22:29
  • “You can’t store different compile time versions in a container” If you need runtime polymorphism, use the runtime version. – Kerndog73 Dec 19 '18 at 22:32
  • “You can’t pass around an instance of the compile time version”. You wouldn’t typically store just a single property in a class like this. std::span stores a runtime pointer and a runtime or compile time size. std::array stores runtime elements and a compile time size. You can call a static function like this compileTimeInstance.getProp(). This means that you can pass either the runtime or compile time version to a template function. – Kerndog73 Dec 19 '18 at 22:36
  • You could pass either a std::array or a std::vector to a template function and it will just work. – Kerndog73 Dec 19 '18 at 22:44
  • @Kerndog73 1. Where did you ever speak of arrays? The question was more general. 2. But you don't need a template specialisation for, have a separate class. 3. Have a close look: std::spanand std::array both have one single template parameter for the type. As mentioned, Type<10> and Type<12> are different types, you cannot place both of them into the same array. Do you want all of your configuration objects to return the same value? 4. see 3. – Aconcagua Dec 20 '18 at 5:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.