fnc12 / sqlite_orm

❤️ SQLite ORM light header only library for modern C++
GNU Affero General Public License v3.0
2.32k stars 321 forks source link

Cannot convert condition to tuple in `mapped_view` #1346

Open stevenwdv opened 3 months ago

stevenwdv commented 3 months ago

This is a regression since v1.9. When using iterate (or more generally, mapped_view) with where() (or more generally, a condition), I get an error:

sqlite_orm.h:15971:75: error: no viable conversion from 'sqlite_orm::internal::where_t<sqlite_orm::internal::is_equal_t<std::basic_string<char> MyRecord::*, std::basic_string<char>>>' to 'conditions_type' (aka 'tuple<sqlite_orm::internal::where_t<sqlite_orm::internal::is_equal_t<std::basic_string<char, std::char_traits<char>, std::allocator<char>> MyRecord::*, std::basic_string<char, std::char_traits<char>, std::allocator<char>>>>, sqlite_orm::internal::order_by_t<long MyRecord::*>>')
 15971 |                 storage(storage), connection(std::move(conn)), expression{std::forward<Args>(args)...} {}
       |                                                                           ^~~~~~~~~~~~~~~~~~~~~~~~
sqlite_orm.h:22161:24: note: in instantiation of member function 'sqlite_orm::internal::mapped_view<MyRecord, sqlite_orm::internal::storage_t<...>, sqlite_orm::internal::where_t<sqlite_orm::internal::is_equal_t<std::basic_string<char> MyRecord::*, std::basic_string<char>>>, sqlite_orm::internal::order_by_t<long MyRecord::*>>::mapped_view' requested here
 22161 |                 return {*this, std::move(con), std::forward<Args>(args)...};
       |                        ^
MyStorage.cpp:377:35: note: in instantiation of function template specialization 'sqlite_orm::internal::storage_t<...>::iterate<MyRecord, MyRecord, sqlite_orm::internal::where_t<sqlite_orm::internal::is_equal_t<std::basic_string<char> MyRecord::*, std::basic_string<char>>>, sqlite_orm::internal::order_by_t<long MyRecord::*>>' requested here
  377 |   for (auto& record : mStorage->m.iterate<MyRecord>(
      |                                   ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/tuple:1356:17: note: candidate constructor not viable: no known conversion from 'sqlite_orm::internal::where_t<sqlite_orm::internal::is_equal_t<std::basic_string<char> MyRecord::*, std::basic_string<char>>>' to 'const tuple<where_t<is_equal_t<basic_string<char> MyRecord::*, basic_string<char>>>, order_by_t<long MyRecord::*>> &' for 1st argument
 1356 |       constexpr tuple(const tuple&) = default;
      |                 ^     ~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/tuple:1358:17: note: candidate constructor not viable: no known conversion from 'sqlite_orm::internal::where_t<sqlite_orm::internal::is_equal_t<std::basic_string<char> MyRecord::*, std::basic_string<char>>>' to 'tuple<where_t<is_equal_t<basic_string<char> MyRecord::*, basic_string<char>>>, order_by_t<long MyRecord::*>> &&' for 1st argument
 1358 |       constexpr tuple(tuple&&) = default;
      |                 ^     ~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/tuple:1363:2: note: candidate template ignored: could not match 'tuple' against 'where_t'
 1363 |         tuple(const tuple<_U1, _U2>& __in)
      |         ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/tuple:1377:2: note: candidate template ignored: could not match 'tuple' against 'where_t'
 1377 |         tuple(tuple<_U1, _U2>&& __in)
      |         ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/tuple:1409:2: note: candidate template ignored: could not match 'pair' against 'where_t'
 1409 |         tuple(const pair<_U1, _U2>& __in)
      |         ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/tuple:1423:2: note: candidate template ignored: could not match 'pair' against 'where_t'
 1423 |         tuple(pair<_U1, _U2>&& __in)
      |         ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/tuple:1370:2: note: explicit constructor is not a candidate
 1370 |         tuple(const tuple<_U1, _U2>& __in)
      |         ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/tuple:1384:2: note: explicit constructor is not a candidate
 1384 |         tuple(tuple<_U1, _U2>&& __in)
      |         ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/tuple:1416:2: note: explicit constructor is not a candidate
 1416 |         tuple(const pair<_U1, _U2>& __in)
      |         ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/tuple:1431:2: note: explicit constructor is not a candidate
 1431 |         tuple(pair<_U1, _U2>&& __in)
      |         ^

This is caused by the constructor of mapped_view constructing expression as expression{std::forward<Args>(args)...}, while it should be expression{{std::forward<Args>(args)...}} (construct a struct with a tuple inside).

I can reproduce this with clang 20.0.0, clang 14.0.0, Apple clang 15.0.0, MSVC 19.39.33523, all with C++20.

fnc12 commented 1 month ago

@stevenwdv could you please show the least code which can repro this issue? It will help a lot in creating a unit test which covers this issue to avoid it firing in future again

stevenwdv commented 1 month ago

Hi! Apparently the issue occurs when using iterate with where + order_by, not with only one:

#include <iostream>
#include <string>

#include <sqlite_orm.h>  // v1.9

struct Person {
    std::string name;
    bool dead{};
};

void listPeople(const std::string &path) {
    using namespace sqlite_orm;

    auto storage = make_storage(path,
        make_table("People",
            make_column("name", &Person::name)
        )
    );
    for (const auto &person : storage.iterate<Person>(
        where(c(&Person::dead) == false),
        order_by(&Person::name).asc()
    )) {
        std::cout << person.name << '\n';
    }
}

Working demo on Compiler Explorer%0A++++)%3B%0A++++for+(const+auto+%26person+:+storage.iterate%3CPerson%3E(%0A++++++++where(c(%26Person::dead)+%3D%3D+false),%0A++++++++order_by(%26Person::name).asc()%0A++++))+%7B%0A++++++++std::cout+%3C%3C+person.name+%3C%3C+!'%5Cn!'%3B%0A++++%7D%0A%7D%0A'),l:'5',n:'1',o:'C%2B%2B+source+%231',t:'0')),k:52.158799853640694,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((g:!((h:compiler,i:(compiler:clang1810,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1',verboseDemangling:'0'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!((name:sqlite,ver:'3400')),options:'-std%3Dc%2B%2B20',overrides:!(),selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+x86-64+clang+18.1.0+(Editor+%231)',t:'0')),k:47.84120014635933,l:'4',m:46.49963154016212,n:'0',o:'',s:0,t:'0'),(g:!((h:output,i:(compilerName:'x86-64+clang+(trunk)',editorid:1,fontScale:14,fontUsePx:'0',j:1,wrap:'1'),l:'5',n:'0',o:'Output+of+x86-64+clang+18.1.0+(Compiler+%231)',t:'0')),header:(),l:'4',m:53.50036845983788,n:'0',o:'',s:0,t:'0')),k:47.84120014635933,l:'3',n:'0',o:'',t:'0')),l:'2',n:'0',o:'',t:'0')),version:4)