我正在开发一个处理非类型C函数(SQLite)的库,我想强力输入它.
我们的想法是拥有一个FieldDef强类型,允许用户将原始类型(如int,double和std :: string)绑定到弱db类型.我的问题是库的语义很重,我想添加一些自动类型推导.
所以我有一堆"基本类型":
namespace FieldType {
struct Integer { using rawtype = int; };
struct Real{ using rawtype = double; };
struct Text{ using rawtype = std::string; };
struct Blob{ using rawtype = std::vector<uint8_t>; };
}
Run Code Online (Sandbox Code Playgroud)
我还有一个insert和一个query函数,允许插入和查询表而不使用SQL语句.查询将是纯选择.无论如何.预期用途是:
FieldDef<FieldType::Integer> mId = makeFieldDef("id", FieldType::Integer()).primaryKey().autoincrement();
FieldDef<FieldType::Text> mName = makeFieldDef("name", FieldType::Text());
FieldDef<FieldType::Integer> mValue = makeFieldDef("value", FieldType::Integer());
SQLiteTable::insert(std::make_tuple(mName, mValue), std::make_tuple(record.name, record.value));
std::vector<Record> r;
SQLiteTable::query
(std::make_tuple(mName, mValue), [&r](std::tuple<std::string, int> res) {
r.push_back(Record{std::get<0>(res), std::get<1>(res)});
});
Run Code Online (Sandbox Code Playgroud)
我用这种方式实现了插入:
template <typename ...Ts, …Run Code Online (Sandbox Code Playgroud) 我有一个模板类,必须在调用参数和返回类型为泛型的函数之前执行某些操作.
这是方法:
template <typename ReturnType, typename ...Args>
ReturnType function (Args ...args) {
// prepare for call
// ...
ReturnType rv = makeCall(args...); // [1]
// dismiss the call
// ...
return rv;
}
Run Code Online (Sandbox Code Playgroud)
当然,如果ReturnType没有正确编译它void.当我在这种情况下使用它时:
function<void>(firstArg, secondArg);
Run Code Online (Sandbox Code Playgroud)
编译器响应
error: return-statement with a value, in function returning 'void' [-fpermissive]
指向标有[1]的行.
除了传递-fpermissive给编译器之外还有其他解决方案吗?我宁愿有一个独特的方法,因为我发现可能的解决方案是使用enable_if和实例化不同的版本is_same.
先感谢您.
- 更新 -
这是一个完整的例子.我应该说我们的函数确实是类方法.
#include <type_traits>
#include <iostream>
class Caller {
public:
Caller() {}
template <typename ReturnType, typename ...Arguments>
ReturnType …Run Code Online (Sandbox Code Playgroud) 在MSVC 19.16下,如果类B明确地从类A继承构造函数,并且还定义了自己的构造函数,则忽略继承的构造函数.
class A {
public:
A() {}
A(int x) {}
};
class B : public A {
public:
using A::A;
B(double x) : A() {}
};
int main()
{
B b; // error C2512: 'B': no appropriate default constructor available
// note: see declaration of 'B'
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在gcc下正确编译.任何人都知道它是编译器错误,还是我想念的东西?谢谢.
我正在编写一个开源的sqlite接口库(例如mSqliteCpp),该库使用c ++类和类型正确管理sqlite数据库。
到目前为止,该库大量使用TMP来构建SQL字符串,但是我发现了一个可能以某种方式影响库效率的问题。
我正在使用类来管理字段定义,类定义,查询和语句。基本上是定义一个表或一条SELECT语句,首先使用适当的FieldDef<T>对象定义字段,然后将它们传递给一个语句构建器,该构建器返回格式正确的SQL语句。
例如:
auto fldId = sqlite::makeFieldDef("id", sqlite::FieldType::Integer());
auto fldName = sqlite::makeFieldDef("name", sqlite::FieldType::Text());
auto fldValue = sqlite::makeFieldDef("value", sqlite::FieldType::Real());
sqlite::statements::Select select("Table", fldId, fldName, fldValue);
ASSERT_EQ(select.string(), "SELECT id,name,value FROM Table;");
Run Code Online (Sandbox Code Playgroud)
请注意,每个字段都是FieldType通过传递给makeFieldDef函数的类型强类型化的,但是可以交换具有相似类型的不同字段。因此,ASSERT调用中的SQL语句是在运行时生成的。
我希望至少在某些条件下在编译时构建它们。例如,开发人员可以使用其他类或constexpr关键字。但是目前我不知道是否可以实现。
有哪些可能的模式?是否可以通过TMP静态构建字符串?我正在使用C ++ 11/14。
谢谢。