Wiadomość błędu przy niespełnieniu warunku requires

Wiadomość błędu przy niespełnieniu warunku requires
TR
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 58
1

Hej.
Chciałbym dodać wiadomość błędu w przypadku, gdy warunek requires nie będzie spełniony - coś jak static_cast robi.

Na przykład mam taki kod:

Kopiuj
template<typename T>
concept Nameable = requires() 
{
    T::NAME;
};

struct WithName
{
    static constexpr const auto NAME = "testName";
};
struct WithoutName
{
};

////////////////////////////////////
template<class T>
requires Nameable<T>
class ErrorIfNotNameable
{
public:
    ErrorIfNotNameable()
    {
        cout << "ErrorIfNotNameable(nameable)" << endl;
    }
};

int main()
{
    ErrorIfNotNameable<WithName>{};
    //ErrorIfNotNameable<WithoutName>{}; /// Error
    return 0;
}

Ten fragment kodu działa tak jak tego oczekuję, czyli nie można stworzyć obiektu klasy ErrorIfNotNameable podając mu argument, który nie jest Nameable.
Ja dodatkowo chciałbym wyświetlić konkretną wiadomość błędu np. "Sorry, ale musisz podać Name, bo <powód>".

Jakieś pomysły?

Bartosz36
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 348
2

Słówko kluczowe requires załatwia sprawę na etapie kompilacji, natomiast wyświetlenie wiadomości następowałoby już w czasie życia programu (w runtimie).
Więc jeśli chciałbyś dla nieprawidłowego typu wyświetlić własną wiadomość w oparciu o std::cout lub podobne, to raczej byłoby to niemożliwe jeśli opierasz się o requires.
Myślę, że wyświetlenie własnej wiadomości błędu byłoby możliwe z assert, ale wtedy nie używałbyś requires, którego chcesz przecież użyć.

Dodatkowo: nie widzę niestety nigdzie w dokumentacji wzmianki o dodawaniu własnego ciągu znaków wyświetlanego w przypadku niespełnionego warunku.
Na Twoim przykładzie kodu próbowałem z użyciem parametrów do requires( std::string customMessage ) ale to bez sensu, chyba, że ktoś znajdzie sposób.


Warto zaznaczyć:
Nie potrzebujesz const gdy masz constexpr.
Sprawdź:

Kopiuj
struct WithName
{
    static constexpr auto NAME = "testName";
};

    auto nameable = WithName();
    nameable.NAME = "new name"; // expression must be a modifiable lvalue
TR
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 58
1

Znalazłem rozwiązanie.

Kopiuj
static_assert(Nameable<T>, "My message");
AL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1493
0

@Bartosz36: w runtime możesz zrobić tak:

Kopiuj
template<typename T>
void foo(T bar)
{
       std::cout << "non nameable" << '\n';
}

template <typename T>
requires Nameable<T>
void foo (T bar)
{
   std::cout << bar.NAME << '\n';
}

https://godbolt.org/z/T3qsdY

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.