lundi 5 février 2018

C++ Templates: correct way to return a new type

Sorry for the generic title, but I'm unable to focus the problem.

I have a templatized class method that accept an argument pack and provides a new type in return, to hide the details of the implementation. More specifically, the class handles SQLite queries, and the method calls sqlite3_prepare() to prepare the statement before executing the query.

class Table {
   ...
   template <typename ...Ts>
   class PreparedStatement { ... };

   template <typename ...Ts>
   PreparedStatement<Ts...> prepare(std::tuple<Ts...> tuple) {
      // do something
      return PreparedStatement<Ts...> ( ... );
   }

That works well with "normal" types, but the problem occurs when the arguments are declared const:

const Field<int> fld = createField<int>("name");
...
PreparedStatement<decltype(fld)> s = prepare(make_tuple(fld));

The error is the following:

no match for 'operator =' (operand types are PreparedStatenent<const Field<int>> and PreparedStatement<Field<int>>

I suspect the issue is in my declaration of the function, is there a way to fix this issue and make the function more "elegant" ?

NOTE: I know I can fix the issue by manually declare the s variable, but my doubts are on how the method was implemented.


As Many Asked, here's an example:

#include <tuple>

template <typename T>
struct Field {
};

class Table {
public:
   template <typename ...Ts>
   class PreparedStatement {
       public:
       PreparedStatement() {};
    };

   template <typename ...Ts>
   PreparedStatement<Ts...> prepare(std::tuple<Ts...> tuple) {
      // do something
      return PreparedStatement<Ts...> ( );
   }
};


int main() 
{
    Field<int> fld;  
    Table t;

    Table::PreparedStatement<decltype(fld)> p;
    p = t.prepare(std::make_tuple(fld));

    // here comes the problem
    const Field<int> f2;
    Table::PreparedStatement<decltype(f2)> p2;

    p2 = t.prepare(std::make_tuple(f2));    

    return 0;
}

and here's the compiler output

main.cpp: In function 'int main()': main.cpp:35:39: error: no match for 'operator=' (operand types are 'Table::PreparedStatement >' and 'Table::PreparedStatement >') p2 = t.prepare(std::make_tuple(f2)); ^ main.cpp:10:10: note: candidate: constexpr Table::PreparedStatement >& Table::PreparedStatement >::operator=(const Table::PreparedStatement >&) class PreparedStatement { ^~~~~~~~~~~~~~~~~ main.cpp:10:10: note: no known conversion for argument 1 from 'Table::PreparedStatement >' to 'const Table::PreparedStatement >&' main.cpp:10:10: note: candidate: constexpr Table::PreparedStatement >& Table::PreparedStatement

::operator=(Table::PreparedStatement >&&) main.cpp:10:10: note: no known conversion for argument 1 from 'Table::PreparedStatement >' to 'Table::PreparedStatement >&&'

UPDATE As many noted, I could use auto to deduce the type, but in some condition auto cannot practically be used. One is, for example, if I need to declare the statement in the Class Context. So suppose auto is forbidden for some reason. Isn't any other solution available? See the updated code above.

Aucun commentaire:

Enregistrer un commentaire