2013-05-24 5 views
5

Я пытаюсь использовать некоторые SFINAE внутри шаблонизированной структуры. Я уменьшил мою проблему к следующему и мог бы сделать эту работу:Недопустимое использование неполного типа (SFINAE)

template<bool mybool> 
struct test { 
    void myfunc(); 
}; 

template<bool mybool> 
void test<mybool>::myfunc() { 
    std::cout << "test true" << std::endl; 
} 
template<> 
void test<false>::myfunc() { 
    std::cout << "test false" << std::endl; 
} 

int main(int argc, char ** argv) { 
    test<true> foo; 
    test<false> bar; 
    foo.myfunc(); 
    bar.myfunc(); 
} 

С помощью этого кода я получаю результат:

test true 
test false 

Однако, если я хочу считать, что мой struct test с более чем один шаблон параметра, я попытался адаптации выше, как это:

template<int myint, bool mybool> 
struct test { 
    void myfunc(); 
}; 

template<int myint, bool mybool> 
void test<myint,mybool>::myfunc() { 
    std::cout << "test true" << std::endl; 
} 
template<int myint> 
void test<myint,false>::myfunc() { 
//error: invalid use of incomplete type 'struct test<myint, false>' 
    std::cout << "test false" << std::endl; 
} 

int main(int argc, char ** argv) { 
    test<1,true> foo; 
    test<1,false> bar; 
    foo.myfunc(); 
    bar.myfunc(); 
} 

Я получаю недопустимое использование неполного типа «структура тест».

Я иду в неправильном направлении? Есть ли способ сделать то, что я хочу сделать? Спасибо за помощь!

+0

вы имели в виду 'foo.myfunc()', когда вы писали 'foo.test()'? – bitmask

+0

Во втором примере вы также неверно произвели 'myfunc'. Это должно быть 'my_func'. Пожалуйста, попробуйте свои примеры перед публикацией их. – pmr

ответ

6

Вы не можете частично специализировать функцию-член, вы должны partially specialize полную структуру. Следующий пример будет работать правильно

template<int myint, bool mybool> 
struct test { 
    void my_func(); 
}; 

template<int myint, bool mybool> 
void test<myint,mybool>::my_func() { 
    std::cout << "test true" << std::endl; 
} 

template<int myint> 
struct test<myint, false> { 
    void my_func(); 
}; 

template<int myint> 
void test<myint,false>::my_func() { 
//error: invalid use of incomplete type 'struct test<myint, false>' 
    std::cout << "test false" << std::endl; 
} 

int main(int argc, char ** argv) { 
    test<1,true> foo; 
    test<1,false> bar; 
    foo.my_func(); 
    bar.my_func(); 
} 
+0

Хорошо, попробовал ваше решение, и он работал без изменений. Однако, допустим, у меня есть много атрибутов в моем классе, я действительно не хочу объявлять их в обеих структурах. Но если я объявлю их только в первом, я не смогу получить к ним доступ из специализированного. Есть ли способ для меня не удвоить объявление всего? – Kiplaki

+1

@ Kiplaki да, использование какой-нибудь один основа/черты type. – ForEveR

+0

@ Kiplaki Или отправьте по перегрузке с 'false_type/true_type'. – pmr

3

Если вы хотите, чтобы избежать переопределения свой класс, который вы должны сделать, так как частичная специализация функций (членов) не допускается, вы могли бы разлагаться тип. Это позволит свести к минимуму повторение кода:

template<int myint, bool mybool> 
struct test { 
    char some_var; 
    std::vector<int> more_var; 
    void my_func(); 
}; 

Изменение к:

template<int myint> 
struct test_static { 
    protected: 
    char some_var; 
    std::vector<int> more_var; 
}; 

template <int myint, bool mybool> 
struct test : private test_static<myint> { 
    void my_func() { 
     // default case 
    } 
}; 
template <int myint> 
struct test<myint,false> : private test_static<myint> { 
    void my_func() { 
     // special case 
    } 
}; 

Конечно, если вы хотите полную видимость всех членов снаружи, не делают их protected в первую очередь и использовать public вместо private наследование.

3

Глядя на this question на принцип SFINAE, чтобы обновить свою память, я попытался получить результат, который вы ищете с минимальной избыточности в коде.

Я также проверил wikipedia статью на эту тему, в котором указано мне, что вам нужна функциональность, аналогичную слишком boost::enable_if условно выбрать функцию inmplementation:

// simplified version of boost::enable_if_c and disable_if_c to match your exact need 

template <bool B> 
struct enable_if_c { 
    typedef void type; 
}; 

struct enable_if_c<false>{}; 

template <bool B> 
struct disable_if_c { 
    typename void type; 
}; 

struct disable_if_c<true> {}; 

template<bool mybool, typename T> 
struct test { 
    template <bool d> 
    typename enable_if_c<d>::type my_func_impl(){ 
     cout << "true" << endl; 
    } 
    template <bool d> 
    typename disable_if_c<d>::type my_func_impl(){ 
     cout << "false" << endl; 
    } 
    void my_func(){ my_func_impl<mybool>(); } 
}; 

Вы можете определить my_func_impl тела вне структуры с следующий синтаксис:

template <bool mybool, typename T> 
template <bool d> 
typename enable_if_c<d>::type test<mybool,T>::my_func_impl(){ 
    cout << "true" << endl; 
} 

хитрая точка проблемы заключается в том, что вы не можете полагаться на простую перегрузке, так как вы хотите s ame, прототип функции, отсюда необходимость исключительно определять одну или другую реализацию.

0

Вы можете добавить небольшое улучшение в ответ, предоставленной diderc, лишь на небольшой модификации, который позволяет избежать использования вспомогательной функции, которая будет загрязнять свои функции имена:

Вместо:

template <bool d> 
typename enable_if_c<d>::type my_func_impl(){ 
    cout << "true" << endl; 
} 
template <bool d> 
typename disable_if_c<d>::type my_func_impl(){ 
    cout << "false" << endl; 
} 
void my_func(){ my_func_impl<mybool>(); } 

Просто написать:

template <bool d = mybool> 
typename enable_if_c<d>::type my_func(){ 
    cout << "true" << endl; 
} 
template <bool d = mybool> 
typename disable_if_c<d>::type my_func(){ 
    cout << "false" << endl; 
} 

И если вы можете использовать C++ 11, то вы можете заменить enable_if_c и disable_if_c на std::enable_if.

(я не могу комментировать его ответ, поэтому я отправил свой собственный)

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