使用C ++元编程构建静态字符串

Hap*_*tus 3 c++ template-meta-programming c++11

我正在编写一个开源的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。

谢谢。

max*_*x66 5

我正在寻找的是一种将在编译时使用字符串进行大部分计算的解决方案[...]目前,我只是对如何实现实现感到好奇。

不是您的sqlite问题的答案,而是...如果您的“在编译时使用字符串进行计算”就像串联一样简单...只需使用constexpr和模板元编程即可。

std::string不是,constexpr但是std::array可以。

因此,您可以将假字符串定义为字符数组的别名。

template <std::size_t N>
using fakeStr = std::array<char, N>;
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式将字符串文字转换为伪字符串(使用辅助函数并使用类型特征)

template <std::size_t N, std::size_t ... Is>
constexpr fakeStr<sizeof...(Is)> mFSh (char const (& str)[N],
                                       std::index_sequence<Is...> const &)
 { return { { str[Is]... } }; }

template <std::size_t N>
constexpr auto makeFakeStr (char const (& str)[N])
 { return mFSh(str, std::make_index_sequence<N-1>{}); }
Run Code Online (Sandbox Code Playgroud)

伪字符串连接很简单,如下所示

template <std::size_t N1, std::size_t ... I1s,
          std::size_t N2, std::size_t ... I2s>
constexpr fakeStr<N1+N2> cFSh (fakeStr<N1> const & s1,
                               std::index_sequence<I1s...> const &,
                               fakeStr<N2> const & s2,
                               std::index_sequence<I2s...> const &)
 { return { { s1[I1s]..., s2[I2s]... } }; }


template <std::size_t N1, std::size_t N2>
constexpr auto concatFakeStr (fakeStr<N1> const & s1, fakeStr<N2> const & s2)
 { return cFSh(s1, std::make_index_sequence<N1>{},
               s2, std::make_index_sequence<N2>{}); }
Run Code Online (Sandbox Code Playgroud)

constexpr可以进行如下比较(使用C ++ 17,可以简化辅助函数)

template <std::size_t N1, std::size_t N2, std::size_t ... Is>
constexpr bool cmpFSh (fakeStr<N1> const & s1,
                       fakeStr<N2> const & s2,
                       std::index_sequence<Is...> const &)
 { 
   using unused = bool[];

   bool ret { true };

   (void) unused { true, ret &= s1[Is] == s2[Is] ... };

   return ret;
 }

template <std::size_t N1, std::size_t N2>
constexpr bool compareFakeStr (fakeStr<N1> const & s1, fakeStr<N2> const & s2)
 { return (N1 == N2) && cmpFSh(s1, s2, std::make_index_sequence<N1>{}); }
Run Code Online (Sandbox Code Playgroud)

如果您想要a中std::string的a fakeStr,以下代码(constexpr显然不是)可以帮助您

template <std::size_t N, std::size_t ... Is>
std::string fFSh (fakeStr<N> const & s, std::index_sequence<Is...> const &)
 { return { s[Is]..., '\0' }; }

template <std::size_t N>
auto fromFakeString (fakeStr<N> const & s)
 { return fFSh(s, std::make_index_sequence<N>{}); }
Run Code Online (Sandbox Code Playgroud)

以下是完整的(C ++ 14)工作示例

#include <array>
#include <string>
#include <iostream>
#include <type_traits>

template <std::size_t N>
using fakeStr = std::array<char, N>;

template <std::size_t N, std::size_t ... Is>
constexpr fakeStr<sizeof...(Is)> mFSh (char const (& str)[N],
                                       std::index_sequence<Is...> const &)
 { return { { str[Is]... } }; }

template <std::size_t N>
constexpr auto makeFakeStr (char const (& str)[N])
 { return mFSh(str, std::make_index_sequence<N-1>{}); }


template <std::size_t N1, std::size_t ... I1s,
          std::size_t N2, std::size_t ... I2s>
constexpr fakeStr<N1+N2> cFSh (fakeStr<N1> const & s1,
                               std::index_sequence<I1s...> const &,
                               fakeStr<N2> const & s2,
                               std::index_sequence<I2s...> const &)
 { return { { s1[I1s]..., s2[I2s]... } }; }


template <std::size_t N1, std::size_t N2>
constexpr auto concatFakeStr (fakeStr<N1> const & s1, fakeStr<N2> const & s2)
 { return cFSh(s1, std::make_index_sequence<N1>{},
               s2, std::make_index_sequence<N2>{}); }

template <std::size_t N1, std::size_t N2, std::size_t ... Is>
constexpr bool cmpFSh (fakeStr<N1> const & s1,
                       fakeStr<N2> const & s2,
                       std::index_sequence<Is...> const &)
 { 
   using unused = bool[];

   bool ret { true };

   (void) unused { true, ret &= s1[Is] == s2[Is] ... };

   return ret;
 }

template <std::size_t N1, std::size_t N2>
constexpr bool compareFakeStr (fakeStr<N1> const & s1, fakeStr<N2> const & s2)
 { return (N1 == N2) && cmpFSh(s1, s2, std::make_index_sequence<N1>{}); }


template <std::size_t N, std::size_t ... Is>
std::string fFSh (fakeStr<N> const & s, std::index_sequence<Is...> const &)
 { return { s[Is]..., '\0' }; }

template <std::size_t N>
auto fromFakeString (fakeStr<N> const & s)
 { return fFSh(s, std::make_index_sequence<N>{}); }


int main()
 {
   constexpr auto f1  = makeFakeStr("abcd");
   constexpr auto f2  = makeFakeStr("xyz");
   constexpr auto f12 = concatFakeStr(f1, f2);
   constexpr auto f3  = makeFakeStr("abcdxyz");

   static_assert( true == compareFakeStr(f12, f3), "!" );
   static_assert( false == compareFakeStr(f12, f1), "!" );

   auto s12 = fromFakeString(f12);

   std::cout << s12 << std::endl;
 }
Run Code Online (Sandbox Code Playgroud)

我再说一遍:只是为了玩。