对于通用标题感到抱歉,但我无法集中解决问题。
我有一个模板化的类方法,它接受一个参数包并提供一个新的类型作为回报,以隐藏实现的细节。更具体地说,该类处理SQLite查询,并且方法调用sqlite3_prepare()
以在执行查询之前准备语句。
class Table {
...
template <typename ...Ts>
class PreparedStatement { ... };
template <typename ...Ts>
PreparedStatement<Ts...> prepare(std::tuple<Ts...> tuple) {
// do something
return PreparedStatement<Ts...> ( ... );
}
适用于“普通”类型,但在声明参数const
时会出现问题:
const Field<int> fld = createField<int>("name");
...
PreparedStatement<decltype(fld)> s = prepare(make_tuple(fld));
错误如下:
no match for 'operator =' (operand types are PreparedStatenent<const Field<int>> and PreparedStatement<Field<int>>
我怀疑问题出在我的函数声明中,有没有办法解决这个问题并使函数更“优雅”?
注意:我知道我可以通过手动声明s
变量来解决问题,但我怀疑这个方法是如何实现的。
正如许多人所问,这是一个例子:
#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;
}
这是编译器输出
main.cpp:在函数'int main()'中:main.cpp:35:39:错误:不匹配 'operator ='(操作数类型是'Table :: PreparedStatement&gt;'和'Table :: PreparedStatement&gt;') p2 = t.prepare(std :: make_tuple(f2)); ^ main.cpp:10:10:注意:候选人:constexpr表:: PreparedStatement&gt;&amp; Table :: PreparedStatement&gt; :: operator =(const Table :: PreparedStatement&gt;&amp;) class PreparedStatement { ^ ~~~~~~~~~~~~~~~~ main.cpp:10:10:注意:“Table :: PreparedStatement&gt;”中没有已知的参数1转换 'const Table :: PreparedStatement&gt;&amp;' main.cpp:10:10:注意:候选人:constexpr Table :: PreparedStatement&gt;&amp; 表:: PreparedStatement的
:: operator =(Table :: PreparedStatement&gt;&amp;&amp;)main.cpp:10:10:注意:参数1没有已知的转换 'Table :: PreparedStatement&gt;'至 'Table :: PreparedStatement&gt;&amp;&amp;'
更新
正如许多人所指出的,我可以使用auto
推断出类型,但在某些情况下auto
实际上无法使用。例如,一个是我需要在类上下文中声明语句。
因此,假设auto
由于某种原因被禁止。没有任何其他解决方案可用吗?请参阅上面的更新代码。
答案 0 :(得分:3)
cppreference.com make_tuple告诉我们:
template< class... Types > tuple<VTypes...> make_tuple( Types&&... args );
对于
Ti
中的每个Types...
,Vi
中的相应类型Vtypes...
为std::decay<Ti>::type
除非std::decay
的应用导致 对于某种类型std::reference_wrapper<X>
,X
,在这种情况下推导出来 类型为X&
。
虽然std::decay
除了其他内容,但删除了cv限定符。因此,您的类型不是PreparedStatement<const Field<int>>
,而是PreparedStatement<Field<int>>
。
您可以像manni66提议的那样使用auto
来避免此类问题。
auto s = prepare(make_tuple(fld));
答案 1 :(得分:1)
我可以使用auto来推断类型,但在某些情况下auto实际上不能使用。例如,一个是我需要在类上下文中声明语句。所以假设出于某种原因禁止使用auto。没有任何其他解决方案可用吗?请参阅上面的更新代码。
您可以使用auto
表达式来计算decltype
返回的值,而不是prepare
。
我的意思是......而不是
Table::PreparedStatement<decltype(f2)> p2;
你可以试试
decltype(t.prepare(std::make_tuple(f2))) p2;
或
decltype(std::declval<Table>().prepare(
std::make_tuple(std::declval<Field<int>>()))) p2;
我想您也可以使用类似的decltype()
来声明您的班级成员。