Thread: Metaprogramming Issue

  1. #1
    Registered User
    Join Date
    Oct 2007
    Posts
    5

    Metaprogramming Issue

    I am currently having an issue with C++ metaprogramming system. To be more specific, the issue is about partial template specialisation.

    Suppose I define a template as below:
    Code:
    template<typename T> struct W {...};
    I can specialise W in many different ways. Some examples follow:
    Code:
    template<> struct W<int> {...};
    template<typename T> struct W<T*> {...};
    template<typename T> struct W<const T* const &> {...};
    ...
    I assume it is possible to specialise W (even partially) for any type, may it be defined by myself or not.

    Nevertheless, I am not being able to specialse it for inner classes of template structures. For instance, suppose I define:
    Code:
    template<typename T> struct X {
        ...
        struct Y {...};
    };
    How do I get to specialise W for Y? I tried writting
    Code:
    template<typename T> struct W<typename X<T>::Y> {...};
    without much success.

    Can someone help me with this?

    Thanks in advance.

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You can't do that, for quite a number of reasons.

    First, I'm getting a headache just trying to think my head around the possibilities. I'm pretty sure that qualifies as a reason

    Second, to the compiler, Y is merely a nested type specifier. It might be a typedef. And if it's a typedef, you've got two problems. First, it may not actually be dependent (that is, Y is the same no matter what T is) and the specialization is moot. Second, it may be ambiguous, because if the T of the original template could be int, and any number of X instantiations and specializations may have typedef'd Y to int.

    Third, the effort for the compiler is not justified. It would actually have to instantiate X with every possible type to see if the nested Y fits the one it has.

    And fourth, the whole thing is quite impossible, because of reason #3. You can't know every possible type, because there's an infinite set of them.

    You may say, well, at least it could work for actual inner types of X, say:
    Code:
    W< X<int>::Y > w;
    Clearly, T is int, there, right?

    Not right. I'll show you a pathological case where even this is ambiguous, but first let me rewrite your code to give the various template parameters distinctive names.
    Code:
    template<typename WT> struct W {...};
    template<typename XT> struct X {
        ...
        struct Y {...};
    };
    template<typename WXT> struct W<typename X<WXT>::Y> {...};
    Now we can talk more easily.

    So, you have the above code:
    Code:
    W< X<int>::Y > w;
    Here, WT is X<int>::Y, so XT is int, so the W specialization should be used with WXT deduced to int, right? But remember, X can be specialized too. Consider this specialization:
    Code:
    template <>
    struct X<short>
    {
      typedef X<int>::Y Y;
    };
    Ah, now X<short>::Y and X<int>::Y are the same. What should WXT be now, short or int?

    For that matter, X<user_defined_type_that_just_happens_to_be_here>: :Y is a typedef for X<int>::Y too.


    By the way, this is the same reason why template argument deduction of function templates doesn't work in similar cases:
    Code:
    template <typename T>
    void foo(X<T>::Y y); // T must always be explicitly specified
    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

  3. #3
    Registered User
    Join Date
    Oct 2007
    Posts
    5
    First of all, thanks for answering.

    I see the types can collide because there is no bijection between the XT and Y types.

    But what if the compiler forcefully instances a new Y type for every X. I am willing to tolerate the overhead.

    I just felt that was incorrect because the compiler did not even return a warning when I tried to compile the code above.

    The reason I was using this construct is type traits. In the STL, the iterators are in similar situation to the Y struct, so how come the STL can specialise the iterator_traits class for every possible iterator?

    Can I implement traits differently?

    Thanks in advance.

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Iterator traits aren't specialized for "any type called iterator that is a member of something". std::iterator_traits looks like this:
    Code:
    template <typename It>
    struct iterator_traits
    {
      typedef typename It::category category;
      typedef typename It::value_type value_type;
      typedef typename It::difference_type difference_type;
      typedef typename It::pointer pointer;
      // ...
    };
    
    template <typename T>
    struct iterator_traits<T *>
    {
      typedef random_access_tag category;
      typedef T value_type;
      typedef ptrdiff_t difference_type;
      typedef T *pointer;
      typedef T &reference;
      // ...
    };
    As you can see, the only specialization is for pointers. All other types either have the nested typedefs for iterator_traits to copy, or they fully specialize iterator_traits themselves. (But note that applications may not partially specialize iterator_traits.)

    But what if the compiler forcefully instances a new Y type for every X.
    What do you mean?
    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

  5. #5
    Registered User
    Join Date
    Oct 2007
    Posts
    5
    But what if the compiler forcefully instances a new Y type for every X.
    What do you mean?
    I mean I wish the compiler could differ X<int>::Y from X<short>::Y, even if Y does not take the template parameter into consideration.

    I have been searching around and figured out a partial solution to the matter. What if I could detect at compile time if the template type T is a struct (I can through the T::* work-around) and then use the T::stuff for getting the trait? If T is not a struct, I get traits<T>::stuff to get the trait. The problem with this is verboseness, so I will have to figure out nice macro names.

    Thank you for the help.

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    I can through the T::* work-around
    No, you still can't distinguish between a genuine struct and a typedef for a struct.

    What specific application do you have in mind?
    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

  7. #7
    Registered User
    Join Date
    Oct 2007
    Posts
    5
    Oh, no, I did not mean that.

    I mean there is a way do distinguish, in compile-time, a struct (or a typedef of a struct) against an int or any pre-built type.

    The application I have in mind is a template library. I want to define type traits in order to resolve some information compile time, so that it will be possible to eliminate overheads.

  8. #8
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Boost's type_traits have an is_primitive metafunction.

    You definitely should look at type_traits, enable_if and MPL, all from Boost, if you're doing any metaprogramming.
    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
    Registered User
    Join Date
    Oct 2007
    Posts
    5
    Thank you for the help, I will give a look.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Some weird issue.
    By dbzx in forum C Programming
    Replies: 7
    Last Post: 04-12-2009, 04:10 PM
  2. float calculation issue
    By George2 in forum C# Programming
    Replies: 1
    Last Post: 05-26-2008, 04:56 AM
  3. re-entrancy pattern issue setbacks
    By George2 in forum Windows Programming
    Replies: 0
    Last Post: 04-12-2008, 02:23 AM
  4. type safe issue
    By George2 in forum C++ Programming
    Replies: 4
    Last Post: 02-12-2008, 09:32 PM
  5. my first issue of GDM
    By DavidP in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 09-12-2002, 04:02 PM