2016-03-25 3 views
1

Скажите, у меня есть шаблон, который специализируется на несколько типов, TypeMathcer, в котором есть type участник.Как специализировать шаблон на произвольном зависимом типе

#include <memory> 
#include <vector> 

template <typename T> 
struct TypeMatcher; 

template <typename T> 
struct TypeMatcher<T *> 
{ 
    // making some type from T 
    typedef std::shared_ptr<T> type; 
}; 

template <typename T> 
struct TypeMatcher<T&> 
{ 
    // making other type from T 
    typedef std::vector<T> type; 
}; 

Теперь я хочу, чтобы создать еще один шаблон и специализировать его для типов, которые я получаю от TypeMatcher. Если я делаю это просто, как этот

template <typename T> 
struct MyNeedfullTemplate; 

template <typename T> 
struct MyNeedfullTemplate<typename TypeMatcher<T>::type> 
{  
}; 

Я получаю ошибку компиляции: template parameters not deducible in partial specialization.

же ошибка, если использовать using синтаксис

template <typename T> 
using type_matcher_t = typename TypeMatcher<T>::type; 

template <typename T> 
struct MyNeedfullTemplate; 

template <typename T> 
struct MyNeedfullTemplate<type_matcher_t<T> > 
{ 
}; 

Я прочитал ответ на вопрос partial specialization for iterator type of a specified container type, который очень похож на мой вопрос, но все еще не уверен, что если существующие одного контрпример делает весь вопрос бессмысленным. Также у нас есть совершенно новые стандарты C++ 14 и C++ 17, которые могут изменить ситуацию. Итак, что, если я гарантирую, что специализации уникальны и существуют, будут ли какие-либо возможности сделать параметры выводимыми?

ответ

2

Это невозможно, в принципе, и никакая фантазия C++ 9999 не может изменить это.

Что вы просите компилятор сделать:

Там в использовании таких как MyNeedfulTemplate<int> в коде. Компилятору необходимо определить MyNeedfulTemplate<U> за U = int. Вы пытались обеспечить частичную специализацию формы

template <typename T> 
struct MyNeedfullTemplate<typename TypeMatcher<T>::type> 

Чтобы увидеть, относится ли эта специализация или нет, компилятор должен проверять TypeMatcher<T> для всех возможных T s и найти, если какая-либо один из них вложенный typedef type, что псевдонимы int. Этого не может быть, так как множество «всевозможных T s» бесконечно. OK, TypeMatcher<int> не имеет такого типа, и ни TypeMatcher<int*>, ни TypeMatcher<int**>, ни TypeMatcher<int***>. Но что делать, если TypeMatcher<int****>? Лучше продолжайте пробовать ...

Также помните, что существует частичная и полная специализация, что означает, что сам TypeMatcher может быть специализированным.

Короче говоря, нет нет способ связать int к TypeMatcher<X>::type, если все, что вам это int и не X.


Вы должны быть в состоянии достичь нечто подобное реструктуризации (инвертированный) TypeMatcher немного:

template <class T> 
struct TypeMatcher2 
{ 
    static constexpr specialised = false; 
}; 

template <class T> 
struct TypeMatcher2<std::shared_ptr<T>> 
{ 
    static constexpr specialised = true; 
    using OldType = T*; 
}; 

template <class T> 
struct TypeMatcher2<std::vector<T>> 
{ 
    static constexpr specialised = true; 
    using OldType = T&; 
} 

template <class T, bool spec = TypeMatcher2<T>::specialised> 
struct MyNeedfullTemplate 
{ 
    // generic version 
}; 

template <class T> 
struct MyNeedfullTemplate<T, true> 
{ 
    using OriginalT = typename TypeMatcher2<T>::OldType; 

    // specialised version 
}; 
+0

ОК, я вижу. Но существует ли какой-либо общий шаблон для замены такого шаблона?Что-то вроде черт или, может быть, другое, чего я не знаю. – user2807083

+0

@ user2807083 Я добавил потенциальное решение (предполагая, что я правильно понял ваш случай использования). – Angew

+0

О, это так. Я подозревал, что есть какое-то решение. – user2807083

1

Я думаю, что вы пытаетесь сделать, это:

#include <iostream> 

#include <memory> 
#include <vector> 
#include <utility> 

template <typename T> 
struct TypeMatcher; 

template <typename T> 
struct TypeMatcher<T *> 
{ 
    // making some type from T 
    typedef std::shared_ptr<T> type; 
}; 

template <typename T> 
struct TypeMatcher<T&> 
{ 
    // making other type from T 
    typedef std::vector<T> type; 
}; 


template <typename T, typename = void> 
struct MyNeedfullTemplate; 

template <typename T> 
struct MyNeedfullTemplate<TypeMatcher<T>, std::enable_if_t<std::is_same<typename TypeMatcher<T>::type, std::vector<std::remove_reference_t<T>>>::value>> 
{ 
    static void report() { std::cout << "hello" << std::endl; } 
}; 
int main() 
{ 
    using matcher_type = TypeMatcher<int&>; 
    using full_type = MyNeedfullTemplate<matcher_type>; 
    full_type::report(); 

    return 0; 
} 

Правильно ли я понял вопрос?

+0

Почти, но я не хочу писать разделенную специализацию для каждого типа, подобранную 'TypeMatcher', потому что threre представляет собой бесконечное множество таких типов. – user2807083

+0

Мне нужно было понять, как был решен тип TypeMatcher, прежде чем комментировать дальше. Думаю, –

+0

Я упрощаю пример, я думаю. Основная проблема, с которой я столкнулся, заключалась в вариационных шаблонах и списках типов, из которых я пытаюсь извлечь нечетные и четные типы в виде отдельных списков типов, а не применять 'std :: is_convertible' для каждой пары типов. Ему нужно подумать об этом и, может быть, когда-нибудь я смогу задать правильный вопрос. Все еще не могу сформулировать, что мне нужно. – user2807083

Смежные вопросы