Error the value of systemcoreclock is not usable in a constant expression

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

Странная проблема с constexpr и __FUNCTION__

Тема в разделе «LANGS.C», создана пользователем Rel, 15 авг 2011.

Страница 1 из 2


  1. Rel

    Rel

    Well-Known Member

    Публикаций:

    2

    Регистрация:
    11 дек 2008
    Сообщения:
    4.896

    сделал удобную систему логирования, которая при возникновении ошибок выдает стек вызовов функций… в стеке в режиме дебага лежат строки с названием функций (__FUNCTION__), в режиме релиза лежат хеш-значения имен функций (для уменьшения размера релиза)… написал реализацию хеш-функции времени компиляции в виде constexpr-функции, но столкнулся с неожиданной проблемой… вот код:

    1. // Константификация значения хеша, тк бывает, что для constexpr
    2. // компилятор все же генерирует код времени выполнения
    3. template <uint32_t Const> struct Constantify { enum { Value = Const }; };
    4. // Хеш-функция времени компиляции
    5. constexpr uint32_t Strhash(const char* Str) { /* реализация хеш-функции */ };
    6. uint32_t hash1 = Constantify<Strhash(«Test!»)>::Value; // Нормально вычисляет хеш во времени компиляции
    7. uint32_t hash2 = Constantify<Strhash(__FUNCTION__)>::Value; // Ошибка компиляции

    сообщения ошибки:

    1. /main.cpp:6:76:   in constexpr expansion of «Strhash(((const char*)(& __FUNCTION__)))»
    2. /main.cpp:6:77: ошибка: the value of «__FUNCTION__» is not usable in a constant expression
    3. /main.cpp:6:64: замечание: «__FUNCTION__» was not declared «constexpr»
    4. /main.cpp:6:77: замечание: in template argument for type «unsigned int»

    вообще мне это кажется странным, тк я не могу понять, чем с точки зрения компилятора __FUNCTION__ отличается от обычной константной строки… как пофиксить?

    ЗЫ gcc 4.6.1 если что… ;)


  2. shchetinin

    shchetinin

    Member

    Публикаций:

    0

    Регистрация:
    27 май 2011
    Сообщения:
    715

    Rel

    Где именно в коде? это хоть в контексте функции? :)


  3. Rel

    Rel

    Well-Known Member

    Публикаций:

    2

    Регистрация:
    11 дек 2008
    Сообщения:
    4.896

    само собой в контексте функции…


  4. shchetinin

    shchetinin

    Member

    Публикаций:

    0

    Регистрация:
    27 май 2011
    Сообщения:
    715

    Может быть

    1. const char * lpStr  = __FUNCTION__;
    2. uint32_t hash2 = Constantify<Strhash(lpStr)>::Value;

    Компилятора нет …


  5. Rel

    Rel

    Well-Known Member

    Публикаций:

    2

    Регистрация:
    11 дек 2008
    Сообщения:
    4.896

    так не получится по все той же причине, очевидной компилятору, но не мне:

    1. ошибка: the value of «lpStr» is not usable in a constant expression
  6. shchetininНу уж точно не так, т.к. это неконстантный указатель на константу. Попробуйте так:

    1. char const* const lpStr = __FUNCTION__;
    2. uint32_t hash2 = Constantify<Strhash(lpStr)>::Value;

  7. Rel

    Rel

    Well-Known Member

    Публикаций:

    2

    Регистрация:
    11 дек 2008
    Сообщения:
    4.896

    нет, та же самая ошибка компиляции:

    1. ошибка: the value of «__FUNCTION__» is not usable in a constant expression

    я не понимаю, почему __FUNCTION__ не может быть использовано, как константное выражение…

  8. Rel

    Попробуй сделать чтобы сама constexpr принимала не const char*, а выводила бы массив:

    1. constexpr uint32_t Strhash(const char (&Str)[size]) { … }

  9. Rel

    Rel

    Well-Known Member

    Публикаций:

    2

    Регистрация:
    11 дек 2008
    Сообщения:
    4.896

    ну вообще при такой постановке задачи работает, но дело в том, что вычисление хеша происходит рекурсивно посимвольно… и я не пойму, как при такой постановке мне вызвать Strhash к следующему символу, например подсчет суммы значений символов в моем варианте был бы такой:

    1.  constexpr uint32_t CountSum(const char* Str) { return (*Str) ? (*Str + CountSum(Str + 1)) : (0); }

    а как реализовать рекурсию с массивом в качестве параметра?

  10. Rel

    Очевидно же:

    1. constexpr uint32_t CountSum(const char (&Str)[size], int n = 0)
    2.     return n == size ? 0 : (Str[n] + CountSum(Str, n + 1));

    EDIT: фикс имен.


  11. GoldFinch

    GoldFinch

    New Member

    Публикаций:

    0

    Регистрация:
    29 мар 2008
    Сообщения:
    1.775

    _DEN_
    в constexpr функциях запрещена рекурсия. надо использовать разные шаблонные перегрузки
    http://forum.vingrad.ru/index.php?showtopic=322361&view=findpost&p=2299543

  12. GoldFinch

    Удалено. Думаю… :)

    EDIT: Не, без нормального знания стандарта не могу сообразить :) А что, в C++09 нет какого-нибудь constexpr-ного for_each?


  13. Rel

    Rel

    Well-Known Member

    Публикаций:

    2

    Регистрация:
    11 дек 2008
    Сообщения:
    4.896

    чего-чего? вообще constexpr имеет хоть какую-то ценность только благодаря рекурсии))) такой код собирается нормально и выдает ожидаемый результат:

    1. template <uint32_t N> constexpr uint32_t CountSum(const char (&Str)[N], uint32_t t = 0) { return Str[t] ? (Str[t] + CountSum(Str, t + 1)) : (0); }

    но, извиняйте… я в первый раз плохо проверил))) с __FUNCTION__ в качестве параметра выдает ту же самую ошибку…

  14. Rel

    C++ — это такой язык, в котором вышеуказаный факт ни о чем не говорит.Скорее всего это значит, что компилятор не рассматривает __FUNCTION__ как литерную строку — для него это рантаймовое значение. Если это так, то тут будет баттхерт — с этим ничего не поделать.


  15. GoldFinch

    GoldFinch

    New Member

    Публикаций:

    0

    Регистрация:
    29 мар 2008
    Сообщения:
    1.775

    у меня нет FDIS, однако в http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf написано

    если что-то поменялось — я только рад

  16. Хреново то, что рекурсии через численные шаблонные параметры тут не катят — частичная специализация шаблонных функций запрещена, и как останавливать такие рекурсии — непонятно.


  17. GoldFinch

    GoldFinch

    New Member

    Публикаций:

    0

    Регистрация:
    29 мар 2008
    Сообщения:
    1.775

    _DEN_
    заворачивать функцию в класс, как еще


  18. sergegers

    sergegers

    New Member

    Публикаций:

    0

    Регистрация:
    8 июн 2008
    Сообщения:
    172

    можно использовать как параметр шаблона константную строку с внешним связыванием. фактически будет использоваться её адрес. __FUNCTION__ явно не подходит

  19. GoldFinch

    Макрос + decltype + auto + значение?


  20. sergegers

    sergegers

    New Member

    Публикаций:

    0

    Регистрация:
    8 июн 2008
    Сообщения:
    172

    1.   static const int value = Y * comb<X, Y — 1>::value;
    2.   static const int value = Y;
    3.   return comb<X, Y>::value;
    4.   std::cout << get_comb<1, 5>() << std::endl;

Страница 1 из 2


WASM

Anton9900

0 / 0 / 0

Регистрация: 18.10.2021

Сообщений: 56

1

20.01.2023, 17:26. Показов 176. Ответов 4

Метки нет (Все метки)


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
#include<array>
 
template<unsigned int N>
struct HashTableOpen{
    std::array<int,N> arr;
    int type;
    HashTableOpen(){
        for(size_t i = 0 ; i< N;i++) arr[i] = -1;
    }
};
int main()
{
    int n = 5;
    HashTableOpen<n> h();
}

Как я понимаю как аргументы шаблонов надо использовать значения, которые будут известны уже во время компиляции(поправьте если я не прав). А если мне надо чтобы пользователь сам определял размер — как мне этого добиться?

C++
1
2
3
4
5
6
7
int main()
{
    int n;
    std::cout<<"Enter n";
    std::cin>>n;
    HashTableOpen<n> h();
}

Заранее спасибо

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



3986 / 3255 / 910

Регистрация: 25.03.2012

Сообщений: 12,102

Записей в блоге: 1

20.01.2023, 17:28

2

Цитата
Сообщение от Anton9900
Посмотреть сообщение

Как я понимаю как аргументы шаблонов надо использовать значения, которые будут известны уже во время компиляции(поправьте если я не прав). А если мне надо чтобы пользователь сам определял размер — как мне этого добиться?

написать класс без шаблонов.

Добавлено через 1 минуту

судя по всему, это не библиотека. Этот код ты пишешь? Ну вот и пиши без шаблонов и Arrayев



0



0 / 0 / 0

Регистрация: 18.10.2021

Сообщений: 56

20.01.2023, 17:29

 [ТС]

3

Цитата
Сообщение от Kuzia domovenok
Посмотреть сообщение

написать класс без шаблонов.

Я думал есть какое-то иное решение… Мир жесток



0



фрилансер

4478 / 3988 / 870

Регистрация: 11.10.2019

Сообщений: 10,503

20.01.2023, 17:53

4

Anton9900, std::vector<int> может помочь



0



Вездепух

Эксперт CЭксперт С++

10435 / 5704 / 1553

Регистрация: 18.10.2014

Сообщений: 14,101

20.01.2023, 19:19

5

Цитата
Сообщение от Anton9900
Посмотреть сообщение

А если мне надо чтобы пользователь сам определял размер — как мне этого добиться?
[…]
Я думал есть какое-то иное решение… Мир жесток

Есть. Включаете запись пения птиц и журчания воды, садитесь в позу лотоса, расслабляетесь и спокойным тихим голосом повторяете себе под нос «Мне не надо, чтобы пользователь сам определял размер. Пусть этого добивается кто-то другой»



0




Description


Paul Pluzhnikov



2013-11-01 21:30:27 UTC

Google ref: b/11479502

/// --- cut ---
template <const char name[]>
class BaseObject {
 virtual const char* GetName() const {
   return name;
 }
};

const char kName[] = "name";
class Object : public BaseObject<kName> {
};

int main() {
 return 0;
}
/// --- cut ---

Using g++ (GCC) 4.9.0 20131028 (experimental)

g++ -c t.cc
t.cc:9:34: error: 'kName' cannot appear in a constant-expression
 class Object : public BaseObject<kName> {
                                  ^
t.cc:9:39: error: template argument 1 is invalid
 class Object : public BaseObject<kName> {
                                       ^

g++ -c t.cc -std=c++11
t.cc:9:34: error: the value of 'kName' is not usable in a constant expression
 class Object : public BaseObject<kName> {
                                  ^
t.cc:8:12: note: 'kName' was not declared 'constexpr'
 const char kName[] = "name";
            ^

Compiles with Clang.

Analysis by Richard Smith:

This is a GCC bug. It appears to be some sort of confusion in the way GCC handles internal linkage non-type template parameters of pointer type. You can also get GCC to accept the code by marking kName as 'extern'.


Obligatory standards references (relative to N3797):

[temp.param](14.1)/8: "A non-type template-parameter of type "array of T" [...] is adjusted to be of type "pointer to T".

[temp.arg.nontype](14.3.2)/1: "A template-argument for a non-type, non-template template-parameter shall be [...] a constant expression that designates the address of a complete object with static storage duration and external or internal linkage [...] expressed [...] as & id-expression, where the id-expression is the name of an object [...], except that the & may be omitted if the name refers to a[n] [...] array"

Note that "kName" is a constant expression, because it is a glvalue core constant expression whose value refers to an object with static storage duration (see [expr.const](5.19)/4).

[temp.arg.nontype](14.3.2)/5: "The following conversions are performed on each expression used as a non-type template-argument. [...] For a non-type template-parameter of type pointer to object, [...] the array-to-pointer conversion [is] applied."


So BaseObject has a template parameter of type 'const char*', and that parameter can bind to the template argument kName (after array-to-pointer decay). There's no requirement that kName be declared 'constexpr'; its value is not used here, only its address is used.


Comment 1


Kai Tietz



2014-12-10 22:08:51 UTC

Hmm, issue seems to be in too restrictive decl_maybe_constant_var_p function.
We could allow here additional ARRAY_TYPEs with constant, non-vla, and trivial destructors.  Maybe even non-trivial destructors could be ok.  Not sure

Suggested patch, which allows provided testcase to run is:

Index: decl2.c
===================================================================
--- decl2.c     (Revision 218570)
+++ decl2.c     (Arbeitskopie)
@@ -4157,8 +4157,12 @@ decl_maybe_constant_var_p (tree decl)
     return false;
   if (DECL_DECLARED_CONSTEXPR_P (decl))
     return true;
-  return (CP_TYPE_CONST_NON_VOLATILE_P (type)
-         && INTEGRAL_OR_ENUMERATION_TYPE_P (type));
+  if (!CP_TYPE_CONST_NON_VOLATILE_P (type))
+    return false;
+  return ((TREE_CODE (type) == ARRAY_TYPE
+          && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type))
+          && !array_of_runtime_bound_p (type))
+         || INTEGRAL_OR_ENUMERATION_TYPE_P (type));
 }

 /* Complain that DECL uses a type with no linkage.  In C++98 mode this is


Comment 2


Richard Smith



2014-12-10 22:25:58 UTC

(In reply to Kai Tietz from comment #1)
> Hmm, issue seems to be in too restrictive decl_maybe_constant_var_p function.

I don't know how the GCC code is structured, but I don't think that's right; that function appears to be checking whether the value of the variable can be used in a constant expression. The relevant condition here is whether the address of the variable can be used.


Comment 3


Kai Tietz



2014-12-11 10:36:46 UTC

(In reply to Richard Smith from comment #2)
> (In reply to Kai Tietz from comment #1)
> > Hmm, issue seems to be in too restrictive decl_maybe_constant_var_p function.
> 
> I don't know how the GCC code is structured, but I don't think that's right;
> that function appears to be checking whether the value of the variable can
> be used in a constant expression. The relevant condition here is whether the
> address of the variable can be used.

hmm, this function has nothing to do with its value.  AFAIU the comment (and its use) it just checks that a VAR-decl might be a constant.
In general it checks for const and volatile attributes, and assumes for integral/enumeral typed variables that variable is constant.
So a 'const char *' isn't constant - as just the destination the variable is pointing to is constant, but not the variable itself.  For a constant array with trivial destructor, and non-vla size this is different.  The array's name is indeed a constant address, and its content is constant too.  Of course the a variable pointing to into an array isn't constant, but the array itself is.

Anyway I might be wrong here


Comment 4


Jonathan Wakely



2018-03-22 08:57:49 UTC

This was fixed by r249079 on trunk and r249325 for 7.2

    Fix array decay handling in constant expressions.
    
    * parser.c (cp_parser_constant_expression): Check
    potential_rvalue_constant_expression after decay_conversion.
    * pt.c (convert_nontype_argument): Don't require linkage in C++17.

Понравилась статья? Поделить с друзьями:
  • Error the system cannot find the path specified торрент
  • Error the system cannot find the file specified veeam
  • Error the store is configured for another domain тильда
  • Error the store is configured for another domain перевод
  • Error the specified item could not be found in the keychain