C++ templates that accept only certain types

前端 未结 14 2379
一整个雨季
一整个雨季 2020-11-22 11:37

In Java you can define generic class that accept only types that extends class of your choice, eg:

public class ObservableList {
  ...
         


        
相关标签:
14条回答
  • 2020-11-22 11:38

    That's not possible in plain C++, but you can verify template parameters at compile-time through Concept Checking, e.g. using Boost's BCCL.

    As of C++20, concepts are becoming an official feature of the language.

    0 讨论(0)
  • 2020-11-22 11:43

    Well, you could create your template reading something like this:

    template<typename T>
    class ObservableList {
      std::list<T> contained_data;
    };
    

    This will however make the restriction implicit, plus you can't just supply anything that looks like a list. There are other ways to restrict the container types used, for example by making use of specific iterator types that do not exist in all containers but again this is more an implicit than an explicit restriction.

    To the best of my knowledge a construct that would mirror the statement Java statement to its full extent does not exist in current standard.

    There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.

    In C++11, the introduction of concepts should make this easier but I don't think it'll do exactly what you'd want either.

    0 讨论(0)
  • 2020-11-22 11:45

    I suggest using Boost's static assert feature in concert with is_base_of from the Boost Type Traits library:

    template<typename T>
    class ObservableList {
        BOOST_STATIC_ASSERT((is_base_of<List, T>::value)); //Yes, the double parentheses are needed, otherwise the comma will be seen as macro argument separator
        ...
    };
    

    In some other, simpler cases, you can simply forward-declare a global template, but only define (explicitly or partially specialise) it for the valid types:

    template<typename T> class my_template;     // Declare, but don't define
    
    // int is a valid type
    template<> class my_template<int> {
        ...
    };
    
    // All pointer types are valid
    template<typename T> class my_template<T*> {
        ...
    };
    
    // All other types are invalid, and will cause linker error messages.
    

    [Minor EDIT 6/12/2013: Using a declared-but-not-defined template will result in linker, not compiler, error messages.]

    0 讨论(0)
  • 2020-11-22 11:47

    Is there some simple equivalent to this keyword in C++?

    No.

    Depending on what you're trying to accomplish, there might be adequate (or even better) substitutes.

    I've looked through some STL code (on linux, I think it's the one deriving from SGI's implementation). It has "concept assertions"; for instance, if you require a type which understands *x and ++x, the concept assertion would contain that code in a do-nothing function (or something similar). It does require some overhead, so it might be smart to put it in a macro whose definition depends on #ifdef debug.

    If the subclass relationship is really what you want to know about, you could assert in the constructor that T instanceof list (except it's "spelled" differently in C++). That way, you can test your way out of the compiler not being able to check it for you.

    0 讨论(0)
  • 2020-11-22 11:49

    As far as I know this isn't currently possible in C++. However, there are plans to add a feature called "concepts" in the new C++0x standard that provide the functionality that you're looking for. This Wikipedia article about C++ Concepts will explain it in more detail.

    I know this doesn't fix your immediate problem but there are some C++ compilers that have already started to add features from the new standard, so it might be possible to find a compiler that has already implemented the concepts feature.

    0 讨论(0)
  • 2020-11-22 11:51

    Executive summary: Don't do that.

    j_random_hacker's answer tells you how to do this. However, I would also like to point out that you should not do this. The whole point of templates is that they can accept any compatible type, and Java style type constraints break that.

    Java's type constraints are a bug not a feature. They are there because Java does type erasure on generics, so Java can't figure out how to call methods based on the value of type parameters alone.

    C++ on the other hand has no such restriction. Template parameter types can be any type compatible with the operations they are used with. There doesn't have to be a common base class. This is similar to Python's "Duck Typing," but done at compile time.

    A simple example showing the power of templates:

    // Sum a vector of some type.
    // Example:
    // int total = sum({1,2,3,4,5});
    template <typename T>
    T sum(const vector<T>& vec) {
        T total = T();
        for (const T& x : vec) {
            total += x;
        }
        return total;
    }
    

    This sum function can sum a vector of any type that support the correct operations. It works with both primitives like int/long/float/double, and user defined numeric types that overload the += operator. Heck, you can even use this function to join strings, since they support +=.

    No boxing/unboxing of primitives is necessary.

    Note that it also constructs new instances of T using T(). This is trivial in C++ using implicit interfaces, but not really possible in Java with type constraints.

    While C++ templates don't have explicit type constraints, they are still type safe, and will not compile with code that does not support the correct operations.

    0 讨论(0)
提交回复
热议问题