Почему clang не компилирует этот код в отличии от gcc
От: niralex  
Дата: 18.03.23 17:51
Оценка:
#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 компилировали?
с++20 clang template constexpr
Re: Почему clang не компилирует этот код в отличии от gcc
От: rg45 СССР  
Дата: 18.03.23 17:57
Оценка:
Здравствуйте, niralex, Вы писали:


N>
N>#include <iostream>
N>#include <array>

N>using namespace std;

N>template<const int *ptr>
N>constexpr const int *Test()
N>{
N>    return ptr + 1;
N>}

N>constexpr array<int, 3> ar{1, 2, 3};

N>int main()
N>{
N>    // clang version 15.0.7 - Compile Error!
N>    // gcc 12.2.0  - ok!!
N>    constexpr auto x = Test<ar.data()>(); // 1

N>    cout << *x << endl;
N>    return 0;
N>}
N>


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
От: niralex  
Дата: 18.03.23 18:26
Оценка:
Здравствуйте, rg45, Вы писали:

R>Не готов диагностировать точно, но думаю, что здесь что-то вокруг типа связывания (linkage). По стандарту параметром шаблона может быть указатель только на данные с внешним связыванием. Похоже, что ar.data() имеет разный тип связывания в clang и в gcc.


Попробовал так:
inline constexpr array<int, 3> ar{1, 2, 3};

Я так понимаю, что теперь ar гарантированно с внешним связыванием. Но проблему это, к сожалению, не решило.
Re: Почему clang не компилирует этот код в отличии от gcc
От: rg45 СССР  
Дата: 18.03.23 18:30
Оценка: 6 (2) +1
Здравствуйте, niralex, Вы писали:


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, то компилер выдает достаточно информативное сообщение:

http://coliru.stacked-crooked.com/a/3feedc4e7b04aa3f

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 та же проблема.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 18.03.2023 19:07 rg45 . Предыдущая версия . Еще …
Отредактировано 18.03.2023 18:31 rg45 . Предыдущая версия .
Отредактировано 18.03.2023 18:31 rg45 . Предыдущая версия .
Re[3]: Почему clang не компилирует этот код в отличии от gcc
От: rg45 СССР  
Дата: 18.03.23 19:50
Оценка: 3 (1)
Здравствуйте, niralex, Вы писали:

N>Я так понимаю, что теперь ar гарантированно с внешним связыванием. Но проблему это, к сожалению, не решило.


Я тут еще поигрался с этим примером, так и эдак. Попробовал заменить std::array собственной структурой. Похоже, что gcc более ранних версий, как и clang, по-видимому, просто не умеют в мемберы. То есть, даже когда полный объект имеет внешнее связывание, его подобъекты таковыми не считаются.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Почему clang не компилирует этот код в отличии от gcc
От: niralex  
Дата: 18.03.23 22:15
Оценка:
Здравствуйте, rg45, Вы писали:

R>Я тут еще поигрался с этим примером, так и эдак. Попробовал заменить std::array собственной структурой. Похоже, что gcc более ранних версий, как и clang, по-видимому, просто не умеют в мемберы. То есть, даже когда полный объект имеет внешнее связывание, его подобъекты таковыми не считаются.


Вопрос еще в том, не является ли это каким-то хаком. Мне просто интересно, это clang еще не допилили или это нестандартная особенность gcc? Clang даже с ключом -std=c++2b не пропускает.
Re: Почему clang не компилирует этот код в отличии от gcc
От: _NN_ www.nemerleweb.com
Дата: 19.03.23 11:03
Оценка: 2 (1)
Здравствуйте, niralex, Вы писали:

У меня нет под рукой заголовочных файлов LLVM, посмотрите как определена функция data:
На синтетическом примере всё собирается:

https://godbolt.org/z/jjEz39rhK

#include <cstdlib>

using namespace std;

struct A
{
    constexpr size_t size() { return 1; }
    constexpr int const* data() const { return nullptr; }
};

A ar;

template<size_t L>
constexpr void f() {}

template<const int * constptr>
constexpr void g()
{
}

int main()
{
    f<ar.size()>();
    g<ar.data()>();
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: Почему clang не компилирует этот код в отличии от gcc
От: σ  
Дата: 20.03.23 15:05
Оценка: 3 (1) +1
N>Вопрос еще в том, не является ли это каким-то хаком. Мне просто интересно, это clang еще не допилили или это нестандартная особенность gcc?

Не допилили.
Re[2]: Почему clang не компилирует этот код в отличии от gcc
От: σ  
Дата: 20.03.23 21:13
Оценка:
R>не является объектом с внешним связыванием

Связывание — это вроде про имена, а не объекты.
Re[3]: Почему clang не компилирует этот код в отличии от gcc
От: rg45 СССР  
Дата: 20.03.23 21:51
Оценка:
Здравствуйте, σ, Вы писали:

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) . . .

--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 20.03.2023 22:02 rg45 . Предыдущая версия . Еще …
Отредактировано 20.03.2023 21:56 rg45 . Предыдущая версия .
Re[4]: Почему clang не компилирует этот код в отличии от gcc
От: σ  
Дата: 24.03.23 09:51
Оценка:
R>Да, с этим не поспоришь, конечно. Но, в то же время, сам стандрат достаточно длительный промежуток времени использовал термин linkage применительно именно к объектам, а не к именам.

https://timsong-cpp.github.io/cppwp/n3337/basic.link#def:linkage в определении вроде не использовал
А ТО, ЧТО В СТАНДАРТЕ В КУЧЕ МЕСТ ПЕРЕПУТАНЫ ОБЪЕКТЫ/ПЕРЕМЕННЫЕ/ИМЕНА ПЕРЕМЕННЫХ — ЭТО НЕ НОВОСТЬ
Re[5]: Почему clang не компилирует этот код в отличии от gcc
От: rg45 СССР  
Дата: 24.03.23 10:24
Оценка:
Здравствуйте, σ, Вы писали:

σ>https://timsong-cpp.github.io/cppwp/n3337/basic.link#def:linkage в определении вроде не использовал


Я с этим и не спорил.

σ>А ТО, ЧТО В СТАНДАРТЕ В КУЧЕ МЕСТ ПЕРЕПУТАНЫ ОБЪЕКТЫ/ПЕРЕМЕННЫЕ/ИМЕНА ПЕРЕМЕННЫХ — ЭТО НЕ НОВОСТЬ


Ну, если уж сам стандарт путается в собственных понятиях, то какой спрос с меня смертного.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: Почему clang не компилирует этот код в отличии от gcc
От: σ  
Дата: 24.03.23 10:49
Оценка: -2
σ>>А ТО, ЧТО В СТАНДАРТЕ В КУЧЕ МЕСТ ПЕРЕПУТАНЫ ОБЪЕКТЫ/ПЕРЕМЕННЫЕ/ИМЕНА ПЕРЕМЕННЫХ — ЭТО НЕ НОВОСТЬ

R>Ну, если уж сам стандарт путается в собственных понятиях, то какой спрос с меня смертного.


А если они головой в унитаз полезут — и ты полезешь?
Re[7]: Почему clang не компилирует этот код в отличии от gcc
От: rg45 СССР  
Дата: 24.03.23 10:51
Оценка: -1 :)
Здравствуйте, σ, Вы писали:

σ>А если они головой в унитаз полезут — и ты полезешь?


Нет просто за щеку тебе завалю и все.

Побыковать решил? Ну-ну, посмотрим.

P.S. Унитазная крышка меня еще не воспитывала.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 25.03.2023 14:35 rg45 . Предыдущая версия . Еще …
Отредактировано 25.03.2023 14:32 rg45 . Предыдущая версия .
Отредактировано 24.03.2023 10:52 rg45 . Предыдущая версия .
Re[2]: Почему clang не компилирует этот код в отличии от gcc
От: vopl Россия  
Дата: 24.03.23 12:32
Оценка: 3 (1) +1
Здравствуйте, _NN_, Вы писали:

_NN>У меня нет под рукой заголовочных файлов LLVM, посмотрите как определена функция data:

_NN>На синтетическом примере всё собирается:

а если так
template<const int *>
void Test() {}

//external
int ar1[3]{};

struct S
{
    int ar[3]{};
} s2;

// internal
namespace
{
    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;
}


как выше заметил ув. σ — не допилили clang
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.