• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Użycie enum class w if constexpr

VPS Starter Arubacloud
0 głosów
198 wizyt
pytanie zadane 18 października 2020 w C i C++ przez NewEraOfPeace Gaduła (4,790 p.)

Cześć. Tutaj krótkie przedstawienie mojego kodu:

enum class draw_opt {
    wrap = 0,
    cut = 1
};

... later in some function

if constexpr(draw_opt::wrap == opt){
    ...
}

 

Mam pewien enum i następnie w funkcji na podstawie tego enuma chcę zrobić X lub Y, jednak nie mogę do tego użyć if constexpr i zastanawiam się dlaczego. Muszę użyć zwyczajnego ifa, obchodzić to jakimiś klasami z static constexpr, czy da się jednak normalnie sprawdzić enum w if constexpr?

komentarz 19 października 2020 przez tkz Nałogowiec (42,000 p.)
A dlaczego chcesz użyć akurat if constexpr?
komentarz 19 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)
Jest to funkcja, która na podstawie wartości enum wpisze do bufora dane w odpowiedni sposób - albo przytnie to co wyjdzie poza zakres jednej linii, albo zrobi word wrap i będzie wypisywać dalej na dole. if constexpr wydał mi się sensowny, z racji, że w if_constexpr będę wybierał tylko ilość bajtów do zapisania.
komentarz 19 października 2020 przez tkz Nałogowiec (42,000 p.)
O ile ten if nie znajduje się w szablonie, to nie widzę sensu by go używać. Kwestią nadrzędną jest, czy wiesz co daje if constexpr.
komentarz 19 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)
Yup, zapewnia, że kompilator wykona pewne rzeczy w czasie kompilacji
komentarz 19 października 2020 przez tkz Nałogowiec (42,000 p.)
No tak i nie, jego zadaniem było zastąpienie poniekąd SFINE. if musiał być poprawny zarówno syntaktycznie, jak i semantycznie, if constexpr tylko syntaktycznie. Jaki błąd generuje kod?
komentarz 19 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)
void Buffer::write_text(std::string_view text, buff_pos bPos, draw_opt opt = draw_opt::wrap){  
    auto indice = posToIndice(bPos, this->width);
    auto remainingToLine = width - this->pos.column;
    
    auto end = remainingToLine;

    if constexpr (draw_opt::wrap == opt){
        auto remainingToEnd = innerBuff.size() - indice + remainingToLine;


        // Ensures, that we will not exceed the buffer
        auto textLen = text.length();
        auto end = textLen - (textLen > remainingToEnd) * textLen - remainingToEnd;
    }


    // Copies from the beggining of the text remainingToLine characters to the inner buffer
    std::copy_n(std::begin(text), end, std::back_inserter(innerBuff));
}

kod (jeszcze nie testowany, mogą być jakieś bugi)

buffer.cpp: In member function 'void Buffer::write_text(std::string_view, buff_pos, draw_opt)':
buffer.cpp:29:40: error: 'opt' is not a constant expression
   29 |     if constexpr (draw_opt::wrap == opt){
      |                                        ^
In file included from E:/msys64/mingw64/include/c++/10.2.0/vector:60,
                 from buffer.h:3,
                 from buffer.cpp:7:
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_algobase.h: In instantiation of 'static constexpr _OI std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m(_II, _II, _OI) [with _II = const char*; _OI = std::back_insert_iterator<std::vector<buff_char> >]':
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_algobase.h:469:12:   required from 'constexpr _OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = const char*; _OI = std::back_insert_iterator<std::vector<buff_char> >]'
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_algobase.h:506:42:   required from 'constexpr _OI std::__copy_move_a1(_II, _II, _OI) [with bool _IsMove = false; _II = const char*; _OI = std::back_insert_iterator<std::vector<buff_char> >]'
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_algobase.h:514:31:   required from 'constexpr _OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = const char*; _OI = std::back_insert_iterator<std::vector<buff_char> >]'
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_algobase.h:569:7:   required from 'constexpr _OI std::copy(_II, _II, _OI) [with _II = const char*; _OI = std::back_insert_iterator<std::vector<buff_char> >]'
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_algo.h:750:23:   required from 'constexpr _OutputIterator std::__copy_n(_RandomAccessIterator, _Size, _OutputIterator, std::random_access_iterator_tag) [with _RandomAccessIterator = const char*; _Size = int; _OutputIterator = std::back_insert_iterator<std::vector<buff_char> >]'
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_algo.h:777:27:   required from 'constexpr _OIter std::copy_n(_IIter, _Size, _OIter) [with _IIter = const char*; _Size = int; _OIter = std::back_insert_iterator<std::vector<buff_char> >]'
buffer.cpp:40:70:   required from here
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_algobase.h:380:18: error: no match for 'operator=' (operand types are 'std::back_insert_iterator<std::vector<buff_char> >' and 'const char')
  380 |        *__result = *__first;
      |        ~~~~~~~~~~^~~~~~~~~~
In file included from E:/msys64/mingw64/include/c++/10.2.0/bits/stl_algobase.h:67,
                 from E:/msys64/mingw64/include/c++/10.2.0/vector:60,
                 from buffer.h:3,
                 from buffer.cpp:7:
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_iterator.h:612:7: note: candidate: 'constexpr std::back_insert_iterator<_Container>& std::back_insert_iterator<_Container>::operator=(const typename _Container::value_type&) [with _Container = std::vector<buff_char>; typename _Container::value_type = buff_char]'
  612 |       operator=(const typename _Container::value_type& __value)
      |       ^~~~~~~~
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_iterator.h:612:56: note:   no known conversion for argument 1 from 'const char' to 'const value_type&' {aka 'const buff_char&'}
  612 |       operator=(const typename _Container::value_type& __value)
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_iterator.h:620:7: note: candidate: 'constexpr std::back_insert_iterator<_Container>& std::back_insert_iterator<_Container>::operator=(typename _Container::value_type&&) [with _Container = std::vector<buff_char>; typename _Container::value_type = buff_char]'
  620 |       operator=(typename _Container::value_type&& __value)
      |       ^~~~~~~~
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_iterator.h:620:51: note:   no known conversion for argument 1 from 'const char' to 'std::vector<buff_char>::value_type&&' {aka 'buff_char&&'}
  620 |       operator=(typename _Container::value_type&& __value)
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_iterator.h:571:11: note: candidate: 'constexpr std::back_insert_iterator<std::vector<buff_char> >& std::back_insert_iterator<std::vector<buff_char> >::operator=(const std::back_insert_iterator<std::vector<buff_char> >&)'
  571 |     class back_insert_iterator
      |           ^~~~~~~~~~~~~~~~~~~~
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_iterator.h:571:11: note:   no known conversion for argument 1 from 'const char' to 'const std::back_insert_iterator<std::vector<buff_char> >&'
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_iterator.h:571:11: note: candidate: 'constexpr std::back_insert_iterator<std::vector<buff_char> >& std::back_insert_iterator<std::vector<buff_char> >::operator=(std::back_insert_iterator<std::vector<buff_char> >&&)'
E:/msys64/mingw64/include/c++/10.2.0/bits/stl_iterator.h:571:11: note:   no known conversion for argument 1 from 'const char' to 'std::back_insert_iterator<std::vector<buff_char> >&&'

błąd

1
komentarz 19 października 2020 przez tkz Nałogowiec (42,000 p.)
Krótko: funkcję można wywołać z parametrami nieznanymi w czasie kompilacji = użyj zwykłego if'a.

Błąd wydaje się dość trywialny, chcesz by kompilator ocenił wyrażenie stałe, stałe w kontekście możliwości oceny w czasie kompilacji używając if constexpr, ale podajesz mu wyrażenie, którego nie da się ocenić w czasie kompilacji.
Na szybko przychodzi mi rozwiązanie z użyciem szablonu. Szablon wymusza na kompilatorze odłożenia nieco w czasie oceny wyrażenia.
Możesz zapoznać się z wymaganiami constexpr ogólnie: https://en.cppreference.com/w/cpp/language/constexpr
komentarz 19 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)

Dziękuję. Napisz to proszę w odpowiedzi, to wleci zielona strzałeczka yes

1
komentarz 19 października 2020 przez tkz Nałogowiec (42,000 p.)
Poczekałbym do jutro, nie czuję się mistrzem w C++. Może ktoś rozwinie, czy doprecyzuje.
komentarz 19 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)
Dobrze, tak czy siak bardzo dziękuję.

1 odpowiedź

+1 głos
odpowiedź 19 października 2020 przez TOM_CPP Pasjonat (22,640 p.)
wybrane 20 października 2020 przez NewEraOfPeace
 
Najlepsza


Jedną z możliwości poprawnego użycia if constexpr jest użycie szablonu funkcji write_text, w którym parametrem będzie draw_opt. Poniżej uproszczony kod:

#include <iostream>

enum class draw_opt {
    wrap = 0,
    cut = 1
};

template< draw_opt opt = draw_opt::wrap >
void write_text( std::string_view text )
{
    std::cout << "Main body of function : " << text << std::endl;
    if constexpr( opt == draw_opt::wrap )
    {
        std::cout << "draw_opt::wrap == opt" << std::endl;
    }
}

int main()
{
    write_text("Call 1");
    std::cout << std::endl;
    write_text<draw_opt::cut>("Call 2");

    return 0;
}

Warto także dodać, że wszystkie zmienne zdefiniowane wewnątrz if constexpr niewidoczne na zewnątrz. Stąd też zmienna end nie będzie widoczna w momencie wywołania std::copy_n i w efekcie dostaniemy błąd kompilacji.

 

komentarz 20 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)

Ponawiam pytanie :)

 

@TOM_CPP, btw. jak mam to zrobić poprawnie dla klasy, kiedy mam osobno w headerze i pliku cpp definicję i deklarację klasy?

1
komentarz 20 października 2020 przez TOM_CPP Pasjonat (22,640 p.)

Zakładam, że chodzi o sytuację  w której  deklaracja metody znajduje się w klasie w pliku  *.h natomiast jej definicja jest zawarta w pliku *.cpp .

Metody szablonowe nie są zwykłymi funkcjami i nie można ich definiować w pliku *.cpp, gdyż nie są one kodem C++, ale szablonem do utworzenia tego kodu. Stąd na etapie kompilacji wymagane jest aby definicja znajdowała się w tym samym pliku co deklaracja. Czyli masz dwa wyjścia: Zdefiniować ją bezpośrednio w klasie, lub też na zewnątrz klasy ale w tym samym pliku (patrz poniżej).

#include <iostream>

// all in *.h file

enum class draw_opt { wrap = 0, cut = 1 };

class Foo
{
public:

template< draw_opt opt = draw_opt::wrap >
void write_text( std::string_view text );

};

template< draw_opt opt >
void Foo::write_text( std::string_view text )
{
    std::cout << "Main body of function : " << text << std::endl;
    if constexpr( opt == draw_opt::wrap )
    {
        std::cout << "draw_opt::wrap == opt" << std::endl;
    }
}

////////////////////////////////////////////////////////////

int main()
{
    Foo foo;

    foo.write_text("Call 1");
    std::cout << std::endl;
    foo.write_text<draw_opt::cut>("Call 2");

    return 0;
}

 

komentarz 20 października 2020 przez NewEraOfPeace Gaduła (4,790 p.)

Supcio. Ostatnie pytanie, á propos dokumentacji kodu. Nigdy tego nie robiem, ale akurat w tym projekcie postanowiem zacząć. Na ten moment dodaję komentarze na początkach plików .cpp i przy deklaracjach funkcji, dając ich krótki opis, opis parametrów i wartości zwracanej (gdzieś tam przy krótkim researchu takie informacje znalazłem), przykładowy plik (nietestowany, nie kompilowany, pewnie są tam jakieś niedopatrzenia/bugi)

pytanie - czy robię to dobrze (może jednak komentarze powinny być przy definicjach?), czy kod jest przez to nieczytelny, czy/(i jak) komentować też argumenty dla templateów?
 

komentarz 20 października 2020 przez tkz Nałogowiec (42,000 p.)
Jeżeli tak Tobie wygodnie, to stosuj takie podejście. Ale skoro piszesz dokumentację za pomocą komentarzy, to może doxygen?
Z reguły swoje projekty dokumentuję za pomocą testów, albo krótkiego pliku z opisem klasy i jej metod. Wszystko zależy jaką metodologię obrałeś, albo jaka została narzucona przez projekt.

Podobne pytania

+1 głos
1 odpowiedź 232 wizyt
pytanie zadane 17 czerwca 2021 w C i C++ przez Eriss69 Gaduła (4,470 p.)
0 głosów
1 odpowiedź 192 wizyt
pytanie zadane 26 września 2022 w C i C++ przez RufinB Obywatel (1,830 p.)
+11 głosów
0 odpowiedzi 317 wizyt
pytanie zadane 17 czerwca 2016 w Nasze poradniki przez MetGang Nałogowiec (34,360 p.)

92,453 zapytań

141,262 odpowiedzi

319,086 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...