Частичная специализация шаблонов для типов переменных и пакетов аргументов, расширенных до внешнего типа, приводит к неоднозначности - PullRequest
1 голос
/ 20 марта 2012

Я пытаюсь скомпилировать следующую программу с g ++ - 4.7 (20120228-1):

#include <cstdlib>
#include <tuple>

template<typename X> struct Y {};

template<typename T, size_t Level, size_t TermLevel> struct A;

// (B) dummy for T=tuple<int, Ts...> just to show it works for simple expansions
template<typename ... Ts, size_t Level, size_t TermLevel>
struct A<std::tuple<int, Ts...>, Level, TermLevel>
{
    A<std::tuple<int, Ts...>, Level+1, TermLevel> value;
};

template<typename ... Ts, size_t Level>
struct A<std::tuple<int, Ts...>, Level, Level> {};


// (C) ambiguous partial specialization
template<typename ... Ts, size_t Level, size_t TermLevel>
struct A<std::tuple<Y<Ts>...>, Level, TermLevel>
{
    A<std::tuple<Y<Ts>...>, Level+1, TermLevel> value;
};

template<typename ... Ts, size_t Level>
struct A<std::tuple<Y<Ts>...>, Level, Level> {};


int main(int argc, const char *argv[])
{
    A<std::tuple<int, float, int>, 0, 5> tint;
    A<std::tuple<Y<int>, Y<float>>, 0, 1> tn;
    return 0;
}

, что приводит к неопределенности следующим образом:

g++-4.7 -g -O0 -std=c++0x    specialization_orig.cc   -o specialization_orig
specialization_orig.cc: In instantiation of 'struct A<std::tuple<Y<int>, Y<float> >, 0ul, 1ul>':
specialization_orig.cc:33:43:   required from here
specialization_orig.cc:23:49: error: ambiguous class template instantiation for 'struct A<std::tuple<Y<int>, Y<float> >, 1ul, 1ul>'
specialization_orig.cc:21:8: error: candidates are: struct A<std::tuple<Y<Ts>...>, Level, TermLevel>
specialization_orig.cc:27:8: error:                 struct A<std::tuple<Y<Ts>...>, Level, Level>
specialization_orig.cc:23:49: error: 'A<std::tuple<Y<Ts>...>, Level, TermLevel>::value' has incomplete type
specialization_orig.cc:6:61: error: declaration of 'struct A<std::tuple<Y<int>, Y<float> >, 1ul, 1ul>'

это немного странно, поскольку расширение аргументов с переменным аргументом работает для простого расширения пакета аргументов, но завершается неудачно, как только пакеты с вариационными аргументами расширяются для вложения в какой-либо другой тип шаблона.

Это просто безумие компилятора или я делаю что-то ужасно неправильное?

1 Ответ

0 голосов
/ 21 марта 2012

Это похоже на ошибку GCC, потому что двусмысленность исчезнет, ​​если вы замените пакет параметров с фиксированным числом параметров: http://ideone.com/6D4Fi.

Этот вид неоднозначности также можно устранить с помощьюstd::enable_if.

/* add "typename = void" anonymous parameter which enables individual partial
   specializations by matching the void result in std::enable_if<>::type. */
template<typename T, size_t Level, size_t TermLevel, typename = void> struct A;

// No enable_if needed here: always enabled if the levels are equal.
template<typename ... Ts, size_t Level>
struct A<std::tuple<int, Ts...>, Level, Level, void> {}; // just pass void

// Use enable_if to disable in case the levels are equal.
template<typename ... Ts, size_t Level, size_t TermLevel>
struct A<std::tuple<Y<Ts>...>, Level, TermLevel,
    typename std::enable_if< Level != TermLevel >::type >
...