Имам доста интересен проблем: имам два шаблонни класа. Единият може да приема произволен параметър на шаблона, другият е по-специализиран (за този проблем с играчката ще кажем, че трябва да приема плаващи точки).
template< class T >
class CanBeAnything{ /*...*/ };
template< class T >
class MustBeFloat{ static_assert(is_floating_point<T>::value, ""); /*...*/ };
Сега имам друг шаблонен клас Foo. Foo няма ограничения за параметъра на шаблона и функция foo, която приема CanBeAnything
или MustBeFloat
от същия тип. Надявам се да използвам изрично инстанциране на шаблон тук, така че искам претоварването MustBeFloat
да съществува само когато моят параметър на шаблона е с плаваща запетая.
Най-простото решение изглежда е да се специализира Foo, но не ми харесва идеята за дублиране на интерфейса в два класа. Измислих почти работещо CRTP решение с един проблем, който ще спомена след минута
/* Traits object to get the value_type out of foo */
template<class FooType>
class FooTraits{};
/* Helper parent class with floating-point only methods */
template<class Derived, bool isFloatingPoint>
class FooSpecialization {}
template<class Derived>
class FooSpecialization<Derived, true>
{
typedef typename FooTraits<Derived>::value_type value_type;
public:
void foo( MustBeFloat<value_type> & x );
};
/* Front-end interface */
template<class T>
class Foo : public FooSpecialization< Foo<T>, is_floating_point<T>::value >
{
typedef FooSpecialization< Foo<T>, is_floating_point<T>::value > Parent;
typedef typename FooTraits< Foo<T> >::value_type value_type;
public:
void foo( CanBeAnything<value_type> & x );
private:
friend class Parent;
};
template<class T>
class FooTraits< Foo<T> >
{ public: typedef T value_type; };
И така, ето го проблемът: Както е, извикванията към foo( MustBeFloat<value_type> & )
са скрити в дъщерния клас чрез скриване на името и компилаторът ми дава грешка „Няма съответстващо извикване на метод foo“. Ако добавя реда using Parent::foo;
, за да го сваля, получавам грешка „foo не съществува в родителския клас“ при инстанциране на Foo
без плаваща запетая, тъй като методът не съществува толкова далеч.
Някакви идеи? Съгласен съм с изстъргването на цялото това решение, ако е налично по-елегантно/работещо.
РЕДАКТИРАНЕ: Само за пояснение: правя изрично инстанциране тук, поради което имам нужда методът да съществува само ако имам параметър на шаблон с плаваща запетая.
template class Foo<int>;
template class Foo<float>;
Това инстанцира ВСЕКИ член на класа, така че методите, които разчитат на неинстанциране на определени методи, не могат да се използват.
EDIT2: Добре, значи прекалявах с това. Ето решението, което използвам:
template<class T>
class Foo
{
public:
template<class T2>
void foo( MustBeFloat<T2> & x ){ static_assert( std::is_same<T,T2>::value, ""); /* ... */}
void foo( CanBeAnything<T> & x ){ /* ... */ }
};
template class Foo<int>;
template class Foo<float>;
template void Foo::foo<float>(MustBeFloat<float> &);
И всичко работи. Ура! Благодаря на хората, които ми помогнаха да стигна до това решение и измислиха други, по-изобретателни.
foo(CanBeAnything<value_type>&)
вFooSpecialization
. - person Oktalist   schedule 01.05.2014foo(CanBeAnything<value_type>&)
вFooSpecializationBase
. Шест от едното, половин дузина от другото. - person Oktalist   schedule 01.05.2014