#include <iostream>
#include <array>
using namespace std;
template<const int *ptr>
constexpr const int *Test()
{
return ptr + 1;
}
constexpr array<int, 3> ar{1, 2, 3};
int main()
{
// clang version 15.0.7 - Compile Error!
// gcc 12.2.0 - ok!!
constexpr auto x = Test<ar.data()>(); // 1
cout << *x << endl;
return 0;
}
Компилятор clang выдает маловразумительные сообщения:
main.cpp|18|error: no matching function for call to 'Test'|
main.cpp|7|note: candidate template ignored: invalid explicitly-specified argument for template parameter 'ptr'|
Как можно минимально поправить код, чтобы и clang и gcc компилировали?
N>Компилятор clang выдает маловразумительные сообщения: N>main.cpp|18|error: no matching function for call to 'Test'| N>main.cpp|7|note: candidate template ignored: invalid explicitly-specified argument for template parameter 'ptr'|
N>Как можно минимально поправить код, чтобы и clang и gcc компилировали?
Не готов диагностировать точно, но думаю, что здесь что-то вокруг типа связывания (linkage). По стандарту параметром шаблона может быть указатель только на данные с внешним связыванием. Похоже, что ar.data() имеет разный тип связывания в clang и в gcc.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Почему clang не компилирует этот код в отличии от gcc
Здравствуйте, rg45, Вы писали:
R>Не готов диагностировать точно, но думаю, что здесь что-то вокруг типа связывания (linkage). По стандарту параметром шаблона может быть указатель только на данные с внешним связыванием. Похоже, что ar.data() имеет разный тип связывания в clang и в gcc.
N>Компилятор clang выдает маловразумительные сообщения: N>main.cpp|18|error: no matching function for call to 'Test'| N>main.cpp|7|note: candidate template ignored: invalid explicitly-specified argument for template parameter 'ptr'| N>Как можно минимально поправить код, чтобы и clang и gcc компилировали?
На самом деле, этот пример и gcc компилирует только на 20-м стандарте. Если снизиться до C++17, то компилер выдает достаточно информативное сообщение:
main.cpp:16:39: error: '& ar.std::array<int, 3>::_M_elems' is not a valid template argument of type 'const int*' because 'ar.std::array<int, 3>::_M_elems' is not a variable
16 | constexpr auto x = Test<ar.data()>(); // 1
То есть, попросту говоря, массив, инкапсулированный внутри std::array, не является объектом с внешним связывание и поэтому не годится в качестве аргумента шаблона. Вполне вероятно, в clang та же проблема.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, niralex, Вы писали:
N>Я так понимаю, что теперь ar гарантированно с внешним связыванием. Но проблему это, к сожалению, не решило.
Я тут еще поигрался с этим примером, так и эдак. Попробовал заменить std::array собственной структурой. Похоже, что gcc более ранних версий, как и clang, по-видимому, просто не умеют в мемберы. То есть, даже когда полный объект имеет внешнее связывание, его подобъекты таковыми не считаются.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Почему clang не компилирует этот код в отличии от gcc
Здравствуйте, rg45, Вы писали:
R>Я тут еще поигрался с этим примером, так и эдак. Попробовал заменить std::array собственной структурой. Похоже, что gcc более ранних версий, как и clang, по-видимому, просто не умеют в мемберы. То есть, даже когда полный объект имеет внешнее связывание, его подобъекты таковыми не считаются.
Вопрос еще в том, не является ли это каким-то хаком. Мне просто интересно, это clang еще не допилили или это нестандартная особенность gcc? Clang даже с ключом -std=c++2b не пропускает.
Re: Почему clang не компилирует этот код в отличии от gcc
Здравствуйте, σ, Вы писали:
R>>не является объектом с внешним связыванием
σ>Связывание — это вроде про имена, а не объекты.
Да, с этим не поспоришь, конечно. Но, в то же время, сам стандрат достаточно длительный промежуток времени использовал термин linkage применительно именно к объектам, а не к именам.
C++11
14.3.2 Template non-type arguments [temp.arg.nontype]
1 A template-argument for a non-type, non-template template-parameter shall be one of:
— an integral constant-expression of integral or enumeration type; or
— the name of a non-type template-parameter; or
— the address of an object or function with external linkage, including function templates and function
template-ids but excluding non-static class members, expressed as & id-expression where the & is
optional if the name refers to a function or array, or if the corresponding template-parameter is a reference;
or
— a pointer to member expressed as described in 5.3.1 .
Начиная с 14-го, разрешили использование объектов с internal linkage, но связка linkage и object все еще сохраняется:
C++14
14.3.2 Template non-type arguments [temp.arg.nontype]
1 A template-argument for a non-type, non-template template-parameter shall be one of:
— for a non-type template-parameter of integral or enumeration type, a converted constant expression
(5.19) of the type of the template-parameter; or
— the name of a non-type template-parameter; or
— a constant expression (5.19) that designates the address of a complete object with static storage duration
and external or internal linkage or a function with external or internal linkage, including function
templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses)
as & id-expression, where the id-expression is the name of an object or function, except that the
& may be omitted if the name refers to a function or array and shall be omitted if the corresponding
template-parameter is a reference; or
Начиная с 17-го упоминания о linkage уже нет. В 20-м переписали все еще больше. Так что, мои воспоминания о linkage в этом контексте вообще можно отнести к фантомным болям
Связывание, похоже, вообще ни при чем уже. Но вот что существенно, это то, что в 20-м появилось упоминание о подобъектах:
C++20
3 For a non-type template-parameter of reference or pointer type, or for each non-static data member of reference
or pointer type in a non-type template-parameter of class type or subobject thereof, the reference or pointer
value shall not refer to or be the address of (respectively) . . .
--
Не можешь достичь желаемого — пожелай достигнутого.
R>Да, с этим не поспоришь, конечно. Но, в то же время, сам стандрат достаточно длительный промежуток времени использовал термин linkage применительно именно к объектам, а не к именам.
σ>>А ТО, ЧТО В СТАНДАРТЕ В КУЧЕ МЕСТ ПЕРЕПУТАНЫ ОБЪЕКТЫ/ПЕРЕМЕННЫЕ/ИМЕНА ПЕРЕМЕННЫХ — ЭТО НЕ НОВОСТЬ
R>Ну, если уж сам стандарт путается в собственных понятиях, то какой спрос с меня смертного.
А если они головой в унитаз полезут — и ты полезешь?
Re[7]: Почему clang не компилирует этот код в отличии от gcc
Здравствуйте, _NN_, Вы писали:
_NN>У меня нет под рукой заголовочных файлов LLVM, посмотрите как определена функция data: _NN>На синтетическом примере всё собирается:
а если так
template<const int *>
void Test() {}
//externalint ar1[3]{};
struct S
{
int ar[3]{};
} s2;
// internalnamespace
{
int ar3[3]{};
struct S
{
int ar[3]{};
} s4;
}
//////////////////////////////int main()
{
Test<ar1>();
Test<s2.ar>();//тут clang обламывается
Test<ar3>();
Test<s4.ar>();//тут clang обламываетсяreturn 0;
}