Russian Qt Forum

Программирование => С/C++ => Тема начата: __Heaven__ от Февраль 09, 2017, 10:05



Название: [РЕШЕНО] Константное выражение в качестве члена класса.
Отправлено: __Heaven__ от Февраль 09, 2017, 10:05
Привет, друзья!
Прошу помочь разобраться, почему не работают методы класса, помеченные как constexpr в коде ниже.
Я ожидаю, что вместо вызова метода во время компиляции будет подставлено константное значение.
Код
C++ (Qt)
#include <QSize>
struct MyStruct
{
   int width() const;
   static constexpr QSize size{20, 20};
};
 
 
int MyStruct::width() const
{
   return size.width();
}
 
int main()
{
   MyStruct().width();
   return 0;
}
 
Цитировать
undefined reference to `MyStruct::size'


Название: Re: Константное выражение в качестве члена класса.
Отправлено: Пантер от Февраль 09, 2017, 10:19
static зачем?


Название: Re: Константное выражение в качестве члена класса.
Отправлено: __Heaven__ от Февраль 09, 2017, 11:06
Нельзя константное выражение делать членом класса без использования static.


Название: Re: Константное выражение в качестве члена класса.
Отправлено: panAlexey от Февраль 09, 2017, 11:10
Код:
int MyStruct::width() const
{
    return MyStruct::size.width();
}
не?


Название: Re: Константное выражение в качестве члена класса.
Отправлено: __Heaven__ от Февраль 09, 2017, 11:35
Код:
int MyStruct::width() const
{
    return MyStruct::size.width();
}
не?
не.

Кажется проблема в QSize, но это не точно. Следующий код работает.

Код
C++ (Qt)
class Size {
double w,h;
public:
constexpr Size(double w, double h)
: w(w), h(h){}
 
constexpr double width() const{
return w;
}
 
constexpr double height() const{
return h;
}
};
 
struct MyStruct
{
   int width() const;
   static constexpr Size size{20, 20};
};
 
 
int MyStruct::width() const
{
   return size.width();
}
 
int main(void) {
MyStruct().width();
return 0;
}


Название: Re: Константное выражение в качестве члена класса.
Отправлено: __Heaven__ от Февраль 09, 2017, 11:46
Немного ошибся насчёт полной работоспособности предыдущего поста.

Попробовал 4 компилятора (clang, gcc, mingw32, mingw64)
Почему-то в gcc подобных код из поста #1 компилится только в release версии. Clang не компилит вообще.


Название: Re: Константное выражение в качестве члена класса.
Отправлено: ViTech от Февраль 09, 2017, 12:03
Может как-то так надо:

Код
C++ (Qt)
struct MyStruct
{
   int width() const;
   constexpr Size size() const
   { return Size(20, 20); }
};


Название: Re: Константное выражение в качестве члена класса.
Отправлено: __Heaven__ от Февраль 09, 2017, 12:14
Может как-то так надо:

Код
C++ (Qt)
struct MyStruct
{
   int width() const;
   constexpr Size size() const
   { return Size(20, 20); }
};
Грязный хак :) но работает)))
Но какого лешего не работает исходное решение??

Кстати, компилер странный код генерирует в отсутствие ключей оптимизации. Он будто игнорирует constexpr. См. аттач.


Название: Re: Константное выражение в качестве члена класса.
Отправлено: ViTech от Февраль 09, 2017, 12:48
Чего это хак, да ещё и грязный :)? Чем MyStruct::size() отличается от Size::width()? Такая же constexpr функция. И если оптимизация не задана пользователем, зачем компилятор будет оптимизировать? Попробуйте следующий код. Без оптимизации и с "-O3", например.

Код
C++ (Qt)
class Size {
double w,h;
public:
constexpr Size(double w, double h)
   : w(w), h(h){}
 
constexpr double width() const{
return w;
}
 
constexpr double height() const{
return h;
}
};
 
struct MyStruct
{
   int width() const;
 
   constexpr Size size() const
   { return Size(20, 20); }
};
 
int MyStruct::width() const
{
return size().width();
}
 
int main(void) {
return MyStruct().width();
}
 


Название: Re: Константное выражение в качестве члена класса.
Отправлено: __Heaven__ от Февраль 09, 2017, 13:03
Чего это хак, да ещё и грязный :)?
Да я шучу :) Просто я хотел член класса, а вы вжух и метод предложили.

Ну, с -O3 он хорошо жмётся, что весьма предсказуемо.
Код
ASM
MyStruct::width() const:
       mov     eax, 20
       ret
main:
       mov     eax, 20
       ret
 
Кстати, мой код перестаёт компилиться при включении оптимизирующих опций. Видать constexpr это не обязательство, а объявление возможности (как и с inline).


Название: Re: Константное выражение в качестве члена класса.
Отправлено: __Heaven__ от Февраль 09, 2017, 13:10
Я забыл упомянуть, что за пределами класса константа себя весьма хорошо чувствует - всё штатно.


Название: Re: Константное выражение в качестве члена класса.
Отправлено: ViTech от Февраль 09, 2017, 13:15
Там, заодно по идее, и MyStruct::width() тоже должно быть constexpr, тогда сожмётся ещё лучше :).
Код
C++ (Qt)
struct MyStruct
{
   constexpr double width() const
   { return size().width(); }
 
   constexpr Size size() const
   { return Size(20, 20); }
};
 


Название: Re: Константное выражение в качестве члена класса.
Отправлено: __Heaven__ от Февраль 09, 2017, 13:24
Дык а некуда дальше))) И так уже просто 20 заносится в регистр и выходит)
Специально не стал делать этот метод constexpr, дабы приблизить пример к тому, что у меня в проекте используется.


Название: Re: Константное выражение в качестве члена класса.
Отправлено: __Heaven__ от Февраль 09, 2017, 13:31
А зацените это вот :) Получил в результате издёвок над компилером
Код
C++ (Qt)
class Size {
   double w,h;
public:
   constexpr Size(double w, double h) noexcept
       : w(w), h(h){}
 
   constexpr double width() const noexcept{
       return w;
   }
 
   constexpr double height() const noexcept{
       return h;
   }
};
 
struct MyStruct
{
   constexpr int width() const noexcept;
   static const Size size;
};
constexpr Size MyStruct::size{20, 20};
 
 
constexpr int MyStruct::width() const noexcept
{
   return size.width();
}
 
int main() {
   constexpr int w = MyStruct().width();
   return 0;
}
 

В объявлении MyStruct нет опечатки это всё компилится


Название: Re: Константное выражение в качестве члена класса.
Отправлено: ViTech от Февраль 09, 2017, 13:48
Да, чем дальше в С++, тем больше дров  ;D. Осталось только не запутаться во всех этих способах инициализации, конструкторах и им подобного ).


Название: Re: [РЕШЕНО] Константное выражение в качестве члена класса.
Отправлено: __Heaven__ от Февраль 09, 2017, 14:02
Добавлю для истории, что msvc 2015 такого способа инициализации не одобряет. Проверено для clang, gcc, mingw64.