У меня есть код со следующей структурой:
template <typename T>
struct Foo
{
struct Bar
{
int data;
};
};
Я хочу написать метафункции, которые сообщат мне, является ли тип Foo или Bar. Первый простой:
template <typename T>
struct is_foo : boost::mpl::false_
{};
template <typename T>
struct is_foo<Foo<T> > : boost::mpl::true_
{};
...
BOOST_MPL_ASSERT(( is_foo<Foo<int> > ));
BOOST_MPL_ASSERT_NOT(( is_foo<int> ));
Однако тот же подход не работает для Бара:
template <typename T>
struct is_bar : boost::mpl::false_
{};
template <typename T>
struct is_bar<typename Foo<T>::Bar> : boost::mpl::true_
{};
Этот код отвергается компилятором. GCC говорит:
main.cpp:38:8: error: template parameters not used in partial specialization:
main.cpp:38:8: error: ‘T’
Как ни странно, clang скомпилирует код, но выдаст предупреждение и метафункция не сработает (всегда false):
main.cpp:38:8: warning: class template partial specialization contains a template parameter that can not be deduced;
this partial specialization will never be used
struct is_bar<typename Foo<T>::Bar> : boost::mpl::true_
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:37:20: note: non-deducible template parameter 'T'
template <typename T>
^
Есть ли обходной путь для этой проблемы? Решение, специфичное для С++ 11, было бы хорошо.
typename Foo<T>::Bar
— невыводимый контекст. Это то же самое, что просить компилятор перечислить все возможные аргументы дляFoo
и проверить, соответствует ли какой-либоFoo<U>::Bar
предоставленномуT
. Кроме того,template<class T> void f(typename Foo<T>::bar){}
является таким же невыводимым контекстом, и вам придется указатьT
вручную, чтобы вызвать эту функцию. (Кстати, именно так указывается частичная специализация шаблонов классов.) - person Xeo   schedule 04.12.2012