концептуальный wish you happy debug
От: Кодт Россия  
Дата: 07.11.24 10:38
Оценка: 39 (2) +1 :)
Маленькая глупенькая загадка-вотзефак. Не из рабочего кода, к счастью, но, как говорится, был близок к тому

Представьте себе, что у вас в коде есть функция f(x) и концепт fable, отвечающий на вопрос — можно ли подставить этот тип в f.

Но этот концепт работает... как-то странно!
Поэтому сделаем два одинаковых концепта — просто скопипастим их.
И даже напишем функцию, которая проверяет их оба.

До того, как всё сломалось, — всё работало: https://gcc.godbolt.org/z/dPPE6KrYe

А потом что-то сломалось.
#include <iostream>

template<class T> concept fable1 = requires(const T& t) { f(t); };
template<class T> concept fable2 = requires(const T& t) { f(t); };

template<class T> void g() {
    if constexpr (fable1<T>) {
        std::cout << "fable" << std::endl;
    } else if constexpr (fable2<T>) {
        std::cout << "wtf" << std::endl;
    } else {
        std::cout << "non-fable" << std::endl;
    }
}

struct A{};  // fable
struct B{};  // non-fable
struct C{};  // wtf

.....

void f(A) {}  // fable
void f(C) {}  // fable ???

static_assert( fable1<A> &&  fable2<A>);
static_assert(!fable1<B> && !fable2<B>);
static_assert( fable1<C> !=  fable2<C>);

int main() {
    g<A>();  // fable
    g<B>();  // non-fable
    g<C>();  // wtf
}


Попробуйте догадаться, в чём дело.
А если догадаетесь, то попробуйте написать минималистичный wish-you-happy-debug

Отгадка
  (.....)
static_assert(!fable1<C>);


Вот так вот! https://gcc.godbolt.org/z/jorvdj7MY
Перекуём баги на фичи!
Отредактировано 07.11.2024 10:49 Кодт . Предыдущая версия .
Re: концептуальный wish you happy debug
От: vopl Россия  
Дата: 07.11.24 11:23
Оценка:
Здравствуйте, Кодт, Вы писали:

Судя по всему, к сабжу применимо следующее положение https://timsong-cpp.github.io/cppwp/temp.constr.constr#temp.constr.atomic-3.sentence-5
Re[2]: концептуальный wish you happy debug
От: vopl Россия  
Дата: 07.11.24 11:25
Оценка:
Здравствуйте, vopl, Вы писали:

V>Здравствуйте, Кодт, Вы писали:


V>Судя по всему, к сабжу применимо следующее положение https://timsong-cpp.github.io/cppwp/temp.constr.constr#temp.constr.atomic-3.sentence-5


Ааа нене.. Тут наоборот, единожды инстанцированный концепт оставляет свое старое значение..
Re: концептуальный wish you happy debug
От: serg_joker Украина  
Дата: 07.11.24 22:42
Оценка:
Здравствуйте, Кодт, Вы писали:

К>...

Это жесть, конечно.
Re: концептуальный wish you happy debug
От: F3V  
Дата: 08.11.24 02:13
Оценка: 43 (2)
Здравствуйте, Кодт, Вы писали:

К>До того, как всё сломалось, — всё работало: https://gcc.godbolt.org/z/dPPE6KrYe


К>Попробуйте догадаться, в чём дело.

К>А если догадаетесь, то попробуйте написать минималистичный wish-you-happy-debug

Подглядел отгадку, т.к. с новыми стандартами ещё не знаком.

Если правильно понял мысль, где двое, там и трое соберутся:

#include <iostream>

struct A {};  // fable
struct B {};  // non-fable
struct C {};  // wtf

template<class T, int I = __LINE__> concept fable1 = requires(const T & t) { f(t); I; };
#define FABLE(_class) fable1<_class, __LINE__>

template<class T, int I = __LINE__> void g() {
    if constexpr (fable1<T,I>) {
        std::cout << I << ": " << typeid(T).name() << " fable" << std::endl;
    } else {
        std::cout << I << ": " << typeid(T).name() << " non-fable" << std::endl;
    }
}

void f(A) {}                // fable

static_assert(!FABLE(C));   // LINE 20!

void f(C) {}                // fable ???

static_assert( FABLE(A));
static_assert(!FABLE(B));
static_assert( FABLE(C));   // LINE 26!

int main() {
    g<A>();     // fable
    g<B>();     // non-fable
    g<C, 20>(); // non-fable  LINE 20
    g<C, 26>(); // fable      LINE 26
    g<C>();     // fable
}


https://gcc.godbolt.org/z/359Kdne8z

Но если убрать там I; то на gcc перестанет компилироваться, хотя студия и clang соберут без ошибок.

Интересно, который из них прав будет?
Re: концептуальный wish you happy debug
От: vopl Россия  
Дата: 08.11.24 08:41
Оценка: 103 (8)
Здравствуйте, Кодт, Вы писали:

К>Маленькая глупенькая загадка-вотзефак. Не из рабочего кода, к счастью, но, как говорится, был близок к тому


не знаю пока зачем такое может понадобиться, но удалось организовать перевычисляемые концепты:
template<class T, class Entropy = decltype([]{})> concept fable = requires(const T& t) { f(t); Entropy{}; };

struct C{};
static_assert(!fable<C>);

void f(C);
static_assert(fable<C>);

https://gcc.godbolt.org/z/MPssWecWb
Re[2]: концептуальный wish you happy debug
От: Кодт Россия  
Дата: 08.11.24 10:10
Оценка: 7 (2)
Здравствуйте, F3V, Вы писали:

F3V>Подглядел отгадку, т.к. с новыми стандартами ещё не знаком.


Этот фокус можно и без концептов провернуть. Проблема в точке инстанцирования шаблона (в данном случае — булевой константы со специальным синтаксисом и специальной семантикой).

auto f1(auto x) { return f(x); }
auto f2(auto x) { return f(x); }

char f(auto) { return 0; }

struct A {};

static_assert(sizeof(f1(A{})) == 1);  // инстанцировали f1 здесь (где видна только char f)

int f(A) { return 0; }

static_assert(sizeof(f1(A{})) == 1);
static_assert(sizeof(f2(A{})) == sizeof(int));  // инстанцировали f2 здесь



F3V>Если правильно понял мысль, где двое, там и трое соберутся:


по поводу __LINE__: оно там в паре мест не по делу. Но это не влияет.
F3V>template<class T, int I = __LINE__ /* = 7 */> concept fable1 = requires(const T & t) { f(t); I; };
F3V>template<class T, int I = __LINE__ /* = 10 */> void g() {


F3V>Но если убрать там I; то на gcc перестанет компилироваться, хотя студия и clang соберут без ошибок.


Гусь кеширует значения requires и проверяет, что они изменились.

Минимизировал пример
https://gcc.godbolt.org/z/3xha35EWq

<source>:1:40: error: satisfaction value of atomic constraint 'requires(T t) {f(t);} [with T = A]' changed from 'false' to 'true'


F3V>Интересно, который из них прав будет?


https://timsong-cpp.github.io/cppwp/temp.constr.constr#temp.constr.atomic-3.sentence-5

If, at different points in the program, the satisfaction result is different for identical atomic constraints and template arguments, the program is ill-formed, no diagnostic required.

Диагностика не требуется, но позволительна
Перекуём баги на фичи!
Отредактировано 08.11.2024 10:27 Кодт . Предыдущая версия .
Re[3]: концептуальный wish you happy debug
От: Кодт Россия  
Дата: 08.11.24 10:32
Оценка:
Здравствуйте, vopl, Вы писали:

V>>Судя по всему, к сабжу применимо следующее положение https://timsong-cpp.github.io/cppwp/temp.constr.constr#temp.constr.atomic-3.sentence-5


V>Ааа нене.. Тут наоборот, единожды инстанцированный концепт оставляет свое старое значение..


А дадада! Единожды инстанцированное ограничение тут тоже фигурирует. Хотя и не повлияло.
Перекуём баги на фичи!
Re[3]: концептуальный wish you happy debug
От: F3V  
Дата: 08.11.24 13:34
Оценка:
Здравствуйте, Кодт, Вы писали:

К>по поводу __LINE__: оно там в паре мест не по делу. Но это не влияет.

К>
template<class T, int I = __LINE__ /* = 7 */> concept fable1 = requires(const T & t) { f(t); I; };
template<class T, int I = __LINE__ /* = 10 */> void g() {


Тут был эксперимент: захотелось в местах __LINE__ синтаксически управляемой лексической фазы разбора исходника во время инстанциирования синтаксического шаблона, чтобы обойтись без макроса FABLE и сохранить исходную лексику примера. (Может такую хотелку и реализуют в стандарте каком-нибудь когда-нибудь.)

В качестве воркэраунда, тут нашлась синтаксическая анонимная лямбда.
Re[2]: концептуальный wish you happy debug
От: F3V  
Дата: 08.11.24 13:54
Оценка:
Здравствуйте, vopl, Вы писали:

V>не знаю пока зачем такое может понадобиться, но удалось организовать перевычисляемые концепты:

  decltype(...)
V>
template<class T, class Entropy = decltype([]{})> concept fable = requires(const T& t) { f(t); Entropy{}; };

struct C{};
static_assert(!fable<C>);

void f(C);
static_assert(fable<C>);

https://gcc.godbolt.org/z/MPssWecWb

А полный пример можно увидеть?

https://gcc.godbolt.org/z/dPnYEMqzr

А то всё равно нужно подстановку делать в список классов, что требует изменения кода в остальных местах.
Подсветка среды для старых версий была.

Спасибо!
Отредактировано 08.11.2024 14:36 F3V . Предыдущая версия . Еще …
Отредактировано 08.11.2024 14:17 F3V . Предыдущая версия .
Re[2]: концептуальный wish you happy debug
От: Ip Man Китай  
Дата: 08.11.24 20:21
Оценка: :)))
Здравствуйте, vopl, Вы писали:

V>не знаю пока зачем такое может понадобиться


на интервью спрашивать
Re[3]: концептуальный wish you happy debug
От: johny5 Новая Зеландия
Дата: 10.11.24 12:07
Оценка: :))
Ой, всё.

IM>на интервью спрашивать
Re[2]: концептуальный wish you happy debug
От: vdimas Россия  
Дата: 19.11.24 18:51
Оценка:
Здравствуйте, vopl, Вы писали:

V>не знаю пока зачем такое может понадобиться, но удалось организовать перевычисляемые концепты:

V>
V>template<class T, class Entropy = decltype([]{})> concept fable = requires(const T& t) { f(t); Entropy{}; };
V>


Охренеть.
И это круто, потому что позволяет отследить варианты с уже видимыми или еще нет перегрузками и вообще символами.

А есть внятное объяснение, почему это работает? ))
Re[3]: концептуальный wish you happy debug
От: vopl Россия  
Дата: 20.11.24 08:21
Оценка:
Здравствуйте, vdimas, Вы писали:

V>А есть внятное объяснение, почему это работает? ))


При каждом обращении на значение fable делается заново переисчисление Entropy (в связи с механизмом его поставки через дефолтное значение), а там кложура, которая каждый раз новая/уникальная. Таким образом каждый раз получаем новую инстанцию с новой Entropy, ну и как побочный эффект, перевычисляется наша полезная нагрузка. Кстати, такое не обязательно делать на констрейнтах, можно и на SFINAE
  например
#include <type_traits>

template <class T, auto e, class=void>
struct Fable : std::false_type {};

template <class T, auto e>
struct Fable<T, e, std::void_t<decltype(f(T{}))>> : std::true_type {};

template <class T, auto e = []{}>
constexpr bool fable = Fable<T, e>::value;

struct C{};
static_assert(!fable<C>);

void f(C);
static_assert(fable<C>);
Отредактировано 20.11.2024 10:48 vopl . Предыдущая версия .
Re[4]: концептуальный wish you happy debug
От: vdimas Россия  
Дата: 20.11.24 11:35
Оценка:
Здравствуйте, vopl, Вы писали:

V>там кложура, которая каждый раз новая/уникальная.


Вопрос был про это.
Т.е., выражение одно, а лямбда каждый раз разная.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.