Вопрос

I'm just beginning to learn template metaprogramming tricks that allow you to query about a type.

For example, SFINAE allows us to check if a type has a particular typedef or function at compile time by using overloading and return type sizeof comparisons.

Q: So, why doesn't (correct me if there are better ways in C++11/14) the language provide better mechanisms/interfaces to make these queries regarding a type?

Edit: I'd like to clarify that this isn't a rant (I'm sorry if it sounds that way). Since I'm only beginning to appreciate the power of templates, I want to ensure my thought process isn't messed up.

For each template class/function for which I want to make these queries, I'd have to create a SFINAE specific version. Wouldn't a single interface that asks the compiler "does T have a member called A" or "does T have a function <return type> (arg list)" be a cleaner way? Surely the compiler has all the knowledge associated with user defined types - it just needs to expose this to the programmer for compile time queries.

Q : Is relying on this general functionality a bad way of designing/thinking about templates? Please state your reasons (with examples that accomplish the task w/o querying, if possible) if that's the case.

Это было полезно?

Решение

Template metaprogramming, SFINAE tricks & co. weren't actually designed to do this stuff. Template metaprogramming in C++ was moslty discovered.

Templates started just as means to write type-generic code, more capabilities were added to cover corner cases (SFINAE was born to avoid compiler errors that could happen when unrelated templates were pulled in the same program), then some day someone discovered that the C++ templates provided a Turing-complete metalanguage that allowed to perform queries about types, carry out computations at compile time and the like.

So, template metaprogramming in C++ is ugly to understand, ugly to write, ugly to debug, tragic to compile because it's mostly an abuse of stuff that was intended for other usages. Templates just happened to be so powerful, but none actually designed them for this.

C++11 provides some library support to this usage (and some core language support as well), but that doesn't change the essence of the situation.

Also, if you want my opinion, template metaprogramming is currently heavily abused; with it you can build monstrosities like Boost.Spirit, but you probably shouldn't.

Другие советы

SFINAE feels like a hack because it is. What you want to do is reflection.

Now at first it sounds easy but the basic problem lies in the simple question: how do you know what type an arbitrary object is?

In languages with a VM/runtime which knows every object ever created this is solved by asking the runtime/VM directly. In C++ templates happen to offer you an escape route because at some point a template must be instantiated. At that point of instantiation, the compiler must know the type. SFINAE essentially aims to capture this knowledge at compile time and repurpose it to encode instructions which, when evaluated at run time will produce the correct result to determine the type of instantiated template.

SFINAE also happens to require virtually no additional machinery on top of "ordinary" C++ templates that compilers did not already have to implement in the first place.

In order to do proper reflection at compile time without tricks like SFINAE, for a statically linked program with no external dependencies you merely have to solve the halting problem. Which is something sensible people, compiler authors and even language committees very much would like to avoid.

In order to do it in the general case which includes you writing library code that will be linked against in the future as a DSO by some other code... well you have to do time travel into the future just to check that future code. So yeah, that is not going to be possible.

So you need proper run time information about types and methods in order to do what you really want to do. But SFINAE allows you a shortcut because you can use the fact that you pass the type(s) at instantiation to extract that information using the type variable in the template and the compile time sizeof evaluation to export the compile time type variable as constants in the generated code as a side effect of what template instantiation does. As said, the reason it feels like a hack is because it is one.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top