Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

You're asking for the impossible. What you want is precisely what templates are, but you also want them to not be "templates" for... some bizarre reason.

> I can have an array of T, but I can't specify that T is Numeric?

Sure you can. If you have C++20 concepts:

  template<class T>
  concept Numeric = std::integral<T> || std::floating_point<T>;
  
  template<Numeric T>
  T twice(T x)
  { return x + x; }
Or if you're on a C++11 compiler:

  template<class T>
  typename std::enable_if<
    std::is_arithmetic<T>::value,
    T>::type twice(T x)
  { return x + x; }


the C++ 20 version can be simplified a bit to:

    Numeric auto twice(Numeric auto x)
    { return x + x; }


Probably not a good idea since the caller won't know what the return type is at that point, and the return type would become dependent on the implementation, which breaks function abstraction.

And imagine what would happen when you get a few more 'auto' variables in the return expression. Suddenly your return type will depend on the implementation of your callees. And the code can then quickly become impossible to understand.

auto is overused.


> Suddenly your return type will depend on the implementation of your callees

Why would that be a problem ? It's super common in templates and has never troubled me the least


It might be common practice but it shouldn't be. There are lots of reasons this is a bad idea; here's just a sampling:

1. "My return type is whatever I happen to return" circumvents the ability of the type checker to ensure correctness.

2. More generally, the purpose of a specification (a function declaration in this case) is to declare what is required of a compliant implementation, and to provide a way to check the validity of that implementation. But when you make the types all become auto-deduced, you're basically reducing the specification to a ~ shoulder shrug "it does whatever it does" ~.

3. Moreover, as I alluded to in the comment, it quickly becomes near-impossible to meaningfully separate the definition from the declaration, whether that's because you want to hide it or because you want to compile it separately. Simply put, you lose modularity. It seems like a minor thing when (as in the example) the return value doesn't depend on types inferred from other callees' return values, but as soon as that ceases to be true, you suddenly tie together the implementations of multiple functions. At that point, your functions lose much of their power to abstract away anything, since as soon as you change the return expression for one function, it has the potential to break code (up to and including causing compilation errors) in the the entire chain of callers. (!)

4. Templates end up getting re-instantiated far more often than they need to be (which can slow down both the compilation and the runtime efficiency). You almost certainly don't want '0' and '(size_t)0' to result in duplicate instantiations when dealing with sizes, for instance.

5. Issue #4 can also result warnings/errors/bugs, since now you have a function that returns a different concrete type than you likely intended, which can result in everything from spurious warnings (signed/unsigned casts, for instance) to actual bugs (later truncation of other variables whose types were inferred incorrectly as a result).

6. The code becomes difficult for a human to read too. You now no longer have any idea what types some variables are supposed to be. Not only does this hamper your ability to cross-check the correctness of the implementation itself (just as with the declarations, in #1) but unless your function is trivial, this quickly makes it harder to even understand what the code is doing in the first place, never mind what it's supposed to do.

7. Proxy types become impossible to implement, since they won't undergo the intended conversions anymore.

All this just to reduce keystrokes might be a common trade-off, but a poor one. I can come up with more reasons, but hopefully this gets the point across.


Bah. Leave it to the latest versions of C++ to show me up.


That's the point though, isn't it? To improve on areas that were lacking in older versions. It can be hard to keep up, though!


It's not just the latest version though? C++11 could already do what you wanted.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: