Подтвердить что ты не робот

Частная специализация шаблона для интегральных непиговых параметров и нецелых не-типов, разница между g++ и clang

Ниже приведена простая частичная специализация шаблона:

// #1
template <typename T, T n1, T n2>
struct foo { 
    static const char* scenario() {
        return "#1 the base template";
    }
};

// #2
// partial specialization where T is unknown and n1 == n2
template <typename T, T a>
struct foo<T, a, a> { 
    static const char* scenario() {
        return "#2 partial specialization";
    }
};

Ниже приведены различные результаты по g++ (6.1) и clang++ (3.8.0):

extern const char HELLO[] = "hello";
double d = 2.3;

int main() {
    cout <<   foo<int, 1, 2>                    ::scenario() << endl;                   
    cout <<   foo<int, 2, 2>                    ::scenario() << endl;                   
    cout <<   foo<long, 3, 3>                   ::scenario() << endl;                  
    cout <<   foo<double&, d, d>                ::scenario() << endl;               
    cout <<   foo<double*, &d, &d>              ::scenario() << endl;             
    cout <<   foo<double*, nullptr, nullptr>    ::scenario() << endl;   
    cout <<   foo<int*, nullptr, nullptr>       ::scenario() << endl;      
    cout <<   foo<nullptr_t, nullptr, nullptr>  ::scenario() << endl; 
    cout <<   foo<const char*, HELLO, HELLO>    ::scenario() << endl;
}

результаты по g++ и clang

# | The code | g++ (6.1) | clang++ (3.8.0) |
1 | foo<int, 1, 2> | #1 as expected | #1 as expected |
2 | foo<int, 2, 2> | #2 as expected | #2 as expected |
3 | foo<long, 3, 3> | #2 as expected | #2 as expected |
4 | foo<double&, d, d> | #1 -- why? | #2 as expected |
5 | foo<double*, &d, &d> | #2 as expected | #2 as expected |
6 | foo<double*, nullptr, nullptr> | #2 as expected | #1 -- why? |
7 | foo<int*, nullptr, nullptr> | #2 as expected | #1 -- why? |
8 | foo<nullptr_t, nullptr, nullptr> | #2 as expected | #1 -- why? |
9 | foo<const char*, HELLO, HELLO> | #2 as expected | #2 as expected |

Какой из них правильный?

Код: http://coliru.stacked-crooked.com/a/45ba16c9f021fd84

4b9b3361

Ответ 1

Я думаю, что clang nullptr больше похож на встроенную переменную типа типа in-build int. nullptr фактически не имеет типа. Объявление (определение отсутствует) nullptr_t равно struct nullptr_t nullptr_t;. И ответ на вопрос один, который прав... ответ заключается в том, что оба они правы, потому что есть стандарт, но это разные компиляторы, созданные из разных компаний, поэтому могут быть различия между GNU G++ и Clang. Clang должен быть полностью совместим с G++, но это не так.

Ответ 2

# 4 плохо сформирован, я удивлен, что он компилируется. Во-первых, двойной параметр нельзя использовать как параметр шаблона непигового типа. С другой стороны, шаблон класса использует те же правила, что и шаблоны функций для частичного упорядочения. В стандарте приведен пример "мнимых" функций, сгенерированных для выполнения заказа:

template<int I, int J, class T> class X { };
template<int I, int J> class X<I, J, int> { }; // #1
template<int I>        class X<I, I, int> { }; // #2
template<int I, int J> void f(X<I, J, int>); // A
template<int I>        void f(X<I, I, int>); // B

В вашем примере это выглядит примерно так:

template <typename T, T n1, T n2>
struct foo { 
};

template <typename T, T n1, T n2>
void bar(foo<T, n1, n2>)
{
    std::cout << "a";
}

template <typename T, T a>
void bar(foo<T, a, a>)
{
    std::cout << "b";
}

Вывод аргумента шаблона используется для определения того, какая функция более специализирована, чем другая. A double& следует выводить как double, и поэтому обе специализации должны быть равны, а также для двузначных для bar(foo<double&, d, d>{});. Вот и GCC и Clang жалуются:

Ошибка GCC

main.cpp: 14: 6: примечание: вывод аргумента шаблона/замена failed: main.cpp: 26: 29: note: несогласованные типы 'double &' а также 'Двойной'

 bar(foo<double&, d, d>{});
                         ^

Ошибка Clang

Примечание: шаблон кандидата игнорируется: сбой замены [с T = double &]: выведенный аргумент шаблона не-типа не имеет того же введите в качестве соответствующего параметра шаблона ('double' vs 'double & Амп; ')

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

Я не буду тестировать остальные, но вы можете найти похожие результаты.