Thread: Check at compile time whether one template parameter is derived from another

  1. #1
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396

    Check at compile time whether one template parameter is derived from another

    I have some templates of the form:

    Code:
    template < typename Base, typename Derived >
    void Foo(...)
    Where it should only be instantiated if Derived derives from Base. Currently, I'm using a helper template:

    Code:
    template < typename Base, typename Derived >
    class Inherits
    {
    public:
        Inherits() { Base *b = (Derived *)NULL; }
    };
    Then I instantiate a temporary Inherits< Base, Derived >() when I want to check the constraint.

    Is there a cleverer method?
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  2. #2
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Honestly? The meta-functions `is_true', `is_false', `is_derived_from', and `enable_if' should be in every C++ template programmers tool chest. You should be using them and their kin.

    Anyway, the `Inherits' check should use function overloading and `sizeof' to determine the inheritance as with this approach you don't have to actually instantiate a class to get your logic you only need to call the appropriate meta-function and the fully featured meta-function approach gives you the possibility to further tweak characteristics or simply error with your choice--or nearly your choice--of error message.

    If you need help with any of that just let me know, but you are you so you probably see how to use the suggestion to better effect that what you have.

    Soma

    Code:
    template < typename Base, typename Derived >
    enable_if<is_derived_from<Derived, Base>, void> Foo(...)

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    I was aware of Boost's features in this area, but in this case I'd rather not introduce a dependency. I will look at how Boost implements it, though.

    I suspect that the creation of the temporary would be completely optimized away (except for the effect of the compile-time pointer type check), but I'd rather not have it at all.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    "I was aware of Boost's features [...] not introduce a dependency."

    I wasn't suggesting Boost. The Boost programmers didn't create those tools; they formalized them in a way so I try to use those names--or similar ones.

    I was suggesting that you write them.

    "I suspect that the [...] not have it at all."

    You misunderstood the intent. I'm not worried about a few cycles. (Actually, I'm not worried about a lot of cycles... correct first, fast later.) That check has to be done "at runtime"--even though the relevant code will probably not be in the binary. With it, you lose a lot of potential. The check I suggest has to be done "at compile time". With it, you can use the result anywhere in operation that you might use a `typedef' or a constant integer. This approach gives you a lot of room to implement the behavior you want regardless of the situation.

    Soma

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by phantomotap View Post
    You misunderstood the intent. I'm not worried about a few cycles. (Actually, I'm not worried about a lot of cycles... correct first, fast later.) That check has to be done "at runtime"--even though the relevant code will probably not be in the binary. With it, you lose a lot of potential. The check I suggest has to be done "at compile time". With it, you can use the result anywhere in operation that you might use a `typedef' or a constant integer. This approach gives you a lot of room to implement the behavior you want regardless of the situation.
    I don't think it happens at runtime. The statement:

    Code:
    Base *b = (Derived *)NULL;
    Fails to compile if Derived doesn't inherit Base.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  6. #6
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    I will look at how Boost implements it, though.
    Prepare to be discouraged. It looks like boost has a different implementation for every compiler out there.

  7. #7
    Registered User
    Join Date
    Dec 2008
    Location
    Black River
    Posts
    128
    Maybe something like:

    Code:
    typedef struct {
        char c[2];
    } tester_t;
    
    template<class T>
    struct inherits_checker {
        static tester_t f(...);
        static char f(T*);
    };
    
    template<class T1, class T2>
    struct is_same {
        enum {
            value = 0
        };
    };
    
    template<class T>
    struct is_same<T, T> {
        enum {
            value = 1
        };
    };
    
    template<class T1, class T2>
    struct inherits {
        enum {
            value = sizeof(char) == sizeof(inherits_checker<T1>::f((T2*)0)) &&
             !is_same<T1, T2>::value
        };
    };
    
    struct foo {};
    struct bar : foo {};
    
    int main()
    {
       std::cout << inherits<foo, bar>::value << '\n';
    }
    I followed phantomotap's advice but it looks like my template looks different than what he was thinking. It's possible that I'm missing something since I only did that test.
    Last edited by Ronix; 06-03-2009 at 02:59 PM.

  8. #8
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    If your target compilers have TR1, use its is_base_and_derived trait.

    If not, the implementation goes something like this:
    Code:
    struct false_type { typedef false_type type; const static bool value = false; };
    struct true_type { typedef true_type type; const static bool value = true; };
    
    namespace detail
    {
      struct twochar { char tc[2]; };
      template <int N> struct test_result { typedef false_type type; };
      template <> struct test_result<1> { typedef true_type type; };
      template <typename Base, typename Derived>
      class is_base_and_derived_impl
      {
        static char test(Base*);
        static twochar test(...);
      public:
        typedef typename test_result<sizeof(test((Derived*)0))>::type type;
      };
    }
    
    template <typename Base, typename Derived>
    struct is_base_and_derived :
      public detail::is_base_and_derived_impl<Base, Derived>::type
    {};
    // is_base_and_derived<T, T> should be false
    template <typename T>
    struct is_base_and_derived<T, T> : public false_type {};
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  9. #9
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Barf. I can't believe this is so difficult. Thank Ronix/CornedBee -- I'll bear your solution in mind. But for now I think I'll stick with what I have.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Code review
    By Elysia in forum C++ Programming
    Replies: 71
    Last Post: 05-13-2008, 09:42 PM
  2. Can you compile the following template function code?
    By George2 in forum C++ Programming
    Replies: 8
    Last Post: 03-06-2008, 08:16 PM
  3. Specialising a member function with a template template parameter
    By the4thamigo_uk in forum C++ Programming
    Replies: 10
    Last Post: 10-12-2007, 04:37 AM
  4. Need help with time
    By Gong in forum C++ Programming
    Replies: 7
    Last Post: 01-11-2007, 02:43 PM
  5. oh me oh my hash maps up the wazoo
    By DarkDays in forum C++ Programming
    Replies: 5
    Last Post: 11-30-2001, 12:54 PM