2015-06-19 11 views
2

Этот вопрос предназначен для C++ 03, а не C++ 11.Устранение избыточности с использованием CRTP и множественного наследования

У меня есть случай, когда я использую CRTP с множественным наследованием, и мне любопытно узнать, есть ли способ удалить избыточность, которая создается при указании типа B ниже.

#include "boost/typeof/typeof.hpp" 
#include "boost/units/detail/utility.hpp" 
#include <iostream> 
#include <string> 

struct One{}; 
struct Two{}; 

template<typename T> 
struct Type 
{ 
    static std::string name(void) 
    { 
     return boost::units::detail::demangle(typeid(T).name()); 
    } 
}; 

template<typename T1, 
     typename T2> 
struct A 
{ 
    typedef A<T1, T2> Self; 

    A() 
    { 
     std::cout << Type<Self>::name() << std::endl; 
    } 
}; 

template<typename T1, 
     typename T2, 
     typename T3> 
struct B : public A<One, B<T1, T2, T3> >, // The B<T1, T2, T3> here is redundant 
      public A<Two, B<T1, T2, T3> > 
{ 
    typedef B<T1, T2, T3> Self; 

    B() 
    { 
     std::cout << Type<Self>::name() << std::endl; 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
    B<int, int, int> t; 
    return 0; 
} 

Смотреть это на Coliru

Проблема ухудшается, когда число параметров шаблона для B увеличивается, когда аргументы шаблона сами являются сложными, и когда B унаследован от более A раз. Я хотел бы свести к минимуму повторение параметров шаблона B. В частности, я ищу способ получить доступ к typedef B<T1, T2, T3> Self в списке наследования для B или некоторой эквивалентной версии времени компиляции this.

не могу:

  • Сделать ЬурейиЙ для B выше B с использованием прямого заявления, потому что у меня нет доступа к шаблону параметры
  • Сделать ЬурейуЮ внутри определения наследования, потому что синтаксис не позволяет этого
  • Доступ к typedef изнутри класса, поскольку он еще не существует

Что-то вроде ниже (ни один из которых не правильный код, но отобразить эффект, я ищу):

template<typename T1, 
     typename T2, 
     typename T3> 
struct B : public A<One, Self>, // Cannot access the typedef yet 
      public A<Two, Self> 
{ 
    typedef B<T1, T2, T3> Self; 
}; 

template<typename T1, 
     typename T2, 
     typename T3> 
struct B : typedef B<T1, T2, T3> Self, // Invalid syntax 
      public A<One, Self>, 
      public A<Two, Self> 
{ 

}; 

template<typename T1, 
     typename T2, 
     typename T3> 
struct B : public A<One, B>, // I wish this would work 
      public A<Two, B> 
{ 

}; 

template<typename T1, 
     typename T2, 
     typename T3> 
struct B : public A<One, BOOST_TYPEOF(*this)>, // lol 
      public A<Two, BOOST_TYPEOF(*this)> 
{ 

}; 

Есть ли способ получить доступ к времени компиляции версии this?

+0

Как насчет использования вложенного типа/метафайла? 'template struct M {struct B: A , A {}; }; 'Использование, конечно, не так хорошо в C++ 03 из-за отсутствия шаблонов псевдонимов, но из него можно извлечь:' template struct C: typename M :: B {}; ' – dyp

ответ

0

Проблема:

template<typename T1, 
     typename T2, 
     typename T3> 
struct B : public A<One, B>, // I wish this would work 
      public A<Two, B> 
{ 

}; 

что ваш template <typename T1, typename T2> struct A просит быть создан с T2типа, в то время как то, что вы хотели бы сделать это создать его экземпляр с T2 в шаблон, а именно template<typename, typename,typename> struct B.

Если определение A лежит в собственном контроле, то, возможно, - хотя, возможно, нет - решение , чтобы сделать определение A в соответствии с вашим желанием:

#include "boost/typeof/typeof.hpp" 
#include "boost/units/detail/utility.hpp" 
#include <iostream> 
#include <string> 

struct One{}; 
struct Two{}; 

template<typename T> 
struct Type 
{ 
    static std::string name(void) 
    { 
     return boost::units::detail::demangle(typeid(T).name()); 
    } 
}; 

template<typename T1, 
     template<typename, typename, typename> class T2 
> 
struct A 
{ 

    A() 
    { 
     std::cout << Type<A>::name() << std::endl; 
    } 
}; 


template<typename T1, 
     typename T2, 
     typename T3> 
struct B : public A<One, B >, 
      public A<Two, B > 
{ 
    B() 
    { 
     std::cout << Type<B>::name() << std::endl; 
    } 
}; 


int main(int argc, char* argv[]) 
{ 
    B<int, int, int> t; 
    return 0; 
} 

Эта программа печатает:

A<One, B> 
A<Two, B> 
B<int, int, int> 

цена этого решения ограничивает классы, для которых A может снабдить CRTP базу для тех, что экземпляр шаблона, как B, всего трех параметров typename.

Возможно, вам повезло, что это ограничение не мешает другим пожеланиям вас. Но если вам также понадобится A для создания базы CRTP для классов, которые создают экземпляр некоторого шаблона, который не имеет ровно трех параметров typename, тогда он кусается.

При условии, что все классы, для которых вам нужно A, чтобы снабдить CRTP базы являются реализациями шаблонов, которые имеют только typename параметры, и имеют самое большее N из них, то вы можете все еще есть C++ 03 решение в же духе:

Вы определяете A согласно схеме:

template<typename T1, 
     template<typename /*1*/,.... typename /*N*/> class T2 
> 
struct A { ... }; 

И для каждого шаблона Y, для которых A является б e база CRTP, вы предоставляете точно N параметров, используя параметры «заполнения», которые по умолчанию равны void, при необходимости. Например, если N == 3:

#include "boost/typeof/typeof.hpp" 
#include "boost/units/detail/utility.hpp" 
#include <iostream> 
#include <string> 

struct One{}; 
struct Two{}; 

template<typename T> 
struct Type 
{ 
    static std::string name(void) 
    { 
     return boost::units::detail::demangle(typeid(T).name()); 
    } 
}; 

template<typename T1, 
     template<typename, typename, typename> class T2 
> 
struct A 
{ 

    A() 
    { 
     std::cout << Type<A>::name() << std::endl; 
    } 
}; 


template<typename T1, typename T2 = void, typename T3 = void> 
struct B : public A<One, B >, 
      public A<Two, B > 
{ 
    B() 
    { 
     std::cout << Type<B>::name() << std::endl; 
    } 
}; 

template<typename T1, typename T2, typename T3 = void> 
struct C : public A<One, C >, 
      public A<Two, C > 
{ 
    C() 
    { 
     std::cout << Type<C>::name() << std::endl; 
    } 
}; 

template<typename T1, typename T2, typename T3> 
struct D : public A<One, D >, 
      public A<Two, D > 
{ 
    D() 
    { 
     std::cout << Type<D>::name() << std::endl; 
    } 
}; 



int main(int argc, char* argv[]) 
{ 
    B<int> b; 
    C<int,int> c; 
    D<int,int,int> d; 
    return 0; 
} 

Эта программа печатает:

A<One, B> 
A<Two, B> 
B<int, void, void> 
A<One, C> 
A<Two, C> 
C<int, int, void> 
A<One, D> 
A<Two, D> 
D<int, int, int> 

Правда, более общее решение палочки вас с различного рода «избыточности», в форма тех избыточные параметры шаблона по умолчанию. Но вы, , можете найти его менее раздражительным.

(gcc 5.1/clang 3.6, C++ 03)

+0

Я думаю, что это сработает для моего дела. Большое спасибо! –