У меня есть следующие функции-члена шаблона:Почему функция шаблона по умолчанию выбрана лучше, чем ее специализированная версия?
template <class ParameterT>
typename boost::enable_if_c<boost::is_base_of<BaseOne, ParameterT>::value
|| boost::is_base_of<BaseTwo, ParameterT>::value, void>::type
MyClass::doSomething(const boost::shared_ptr<ParameterT> ¶m);
Вызов doSomething(sharedPtrTo_derivedFromBaseOne)
, doSomething(sharedPtrTo_derivedFromBaseTwo)
или doSomething(sharedPtrTo_derivedFromBaseOneAndBaseTwo)
все работы, называя его с любым другим параметром не работает, что на самом деле то, что я хочу до сих пор.
Теперь, при выполнении вышеизложенного, я хочу еще два звонка: doSomething_baseOne
и doSomething_baseTwo
. Они должны, очевидно, скомпилировать для всех вызовов, которые сделали это до сих пор (так что мой параметр shared_ptr
является либо производным BaseOne
, либо BaseTwo
, либо оба). Я думал, что-то вроде этого:
template<class BaseOneDerived>
void doSomething_baseOne(const boost::shared_ptr<BaseOneDerived> ¶m);
{
std::cout << "doing nothing BaseOne";
}
template<class BaseTwoDerived>
void doSomething_baseTwo(const boost::shared_ptr<BaseTwoDerived> ¶m)
{
std::cout << "doing nothing BaseTwo";
}
//doSomething implementation:
{
doSomething_baseOne(param);
doSomething_baseTwo(param);
}
И doSomething_baseOne
, doSomething_baseTwo
специализаций:
template<>
void MyClass::doSomething_baseOne(const boost::shared_ptr<BaseOne> ¶m)
{
std::cout << "doing something with BaseOne";
}
template<>
void MyClass::doSomething_baseTwo(const boost::shared_ptr<BaseTwo> ¶m)
{
std::cout << "doing something with BaseTwo";
}
Предположат теперь, что у меня есть эта простая иерархия:
class A : public BaseOne {};
class B : public BaseTwo {};
class C : public BaseOne, public BaseTwo {};
Я хотел бы, для следующих вызовов:
MyClass X;
X.doSomething(boost::shared_ptr(new A());
X.doSomething(boost::shared_ptr(new B());
X.doSomething(boost::shared_ptr(new C());
получить следующий вывод:
//for first call
doing something with BaseOne
doing nothing BaseTwo
//for second call
doing nothing BaseOne
doing something with BaseTwo
//for third call
doing something with BaseOne
doing something with BaseTwo
Вместо этого я получаю "ничего не делать с" сообщением 6 раз (на самом деле я не реализовал неспецифические версии, поэтому я действительно получаю ссылку на неопределенное время ссылки, но вы понимаете ее).
Так что в основном компилятор выбирает по умолчанию doSomething_baseOne
и doSomething_baseTwo
в качестве лучших совпадений, чем в специализированных версиях. Почему это? И как я могу преодолеть это, чтобы достичь того, чего хочу?
К сожалению, нет никаких концепций в C++ 03 AFAIK. Я думал, что мне нужно еще немного SFINAE, но на самом деле не было уверен, как это сделать. Таким образом, в основном SFINAE - единственное решение, когда вам нужно просить компилятор выбрать шаблон по умолчанию в качестве «последнего средства»? –
Это другое решение, называемое * отправкой тега *. Это когда-нибудь более читаемо, чем использование триггера enable_if SFINAE. – Oliv
@TedyS. ваш вопрос слишком широк, есть много факторов, которые могут повлиять на разрешение перегрузки, например, вы можете использовать [только один enable_if] (http://melpon.org/wandbox/permlink/iX2ePOel7KCcg4nv), или вы можете использовать [tag -dispatching] (http://melpon.org/wandbox/permlink/huRJhu6wzbJGwEJg) –