gpt4 book ai didi

c++ - 在专用模板中添加运算符重载

转载 作者:太空狗 更新时间:2023-10-29 23:06:48 28 4
gpt4 key购买 nike

想知道 operator , 的有用用途我正在尝试创建一组辅助对象,以便更轻松地从 C++ 代码构建数据库查询。我的想法是利用 operator ,为了创建类似于数据库调用的指令。辅助对象如下:

class Fields
{
public:
Fields &operator ,(const std::string &s)
{
SQL.append(s).append(1, ',');
return *this;
}

Fields &operator ,(const Fields &f)
{
std::string Result = f;
SQL.append(Result);
return *this;
}

virtual operator std::string() const = 0;
protected:
std::string SQL;
};

template <const char *INSTRUCTION> struct Instruction : public Fields
{
operator std::string() const
{
std::string Result(INSTRUCTION);
return Result.append(SQL);
}
};

然后,使用正确的 typedef s 和值,这种方法允许执行以下操作:

extern const char SQL_SELECT[] = "SELECT ";
extern const char SQL_FROM[] = "FROM ";
extern const char SQL_WHERE[] = "WHERE ";
extern const char SQL_ORDER_BY[] = "ORDER BY ";

typedef Instruction<SQL_SELECT> SELECT;
typedef Instruction<SQL_FROM> FROM;
typedef Instruction<SQL_WHERE> WHERE;
typedef Instruction<SQL_ORDER_BY> ORDER_BY;

std::string Query = ((SELECT(), "a", "b", "c"),
(FROM(), "A", "B"),
(WHERE(), "a = b AND c <> b"),
(ORDER_BY(), "a", "c"));

std::cout << Query;

产生此输出:SELECT a,b,c,FROM A,B,WHERE a = b AND c <> b,ORDER_BY a,c, (我正在处理我版本中的尾随逗号,为了缩短示例省略了这部分),here is the code .

问题是指令ORDER BY .该指令可以采用改变排序行为的最终操作数,我想(通过 operator , )将枚举值传递给 struct Instruction实例:

enum ORDER
{
ASC,
DESC,
};

std::string OrderBy = (ORDER_BY(), "a", "c", DESC); // <---- Note the 'DESC' value.

但只想为 Instruction<SQL_ORDER_BY> 启用此运算符实例,所以我尝试专门化模板:

template <> struct Instruction<SQL_ORDER_BY> : public Fields
{
Instruction() : order(ASC) {}

Fields &operator ,(const ORDER o)
{
order = o;
return *this;
}

operator std::string() const
{
std::string Result(SQL_ORDER_BY);
Result.append(SQL);
Result.append(order == ASC? "ASC": "DESC");
return Result;
}

private:
ORDER order;
};

据我所知,这个专业必须有三个 operator ,重载:

  • Fields &operator ,(const Fields &) .
  • Fields &operator ,(const std::string &) .
  • Fields &operator ,(const ORDER) .

但是在创建特化之后,查询字符串:

std::string Query = ((SELECT(), "a", "b", "c"),
(FROM(), "A", "B"),
(WHERE(), "a = b AND c <> b"),
(ORDER_BY(), "a", "c"));

结束值为:SELECT a,b,c,FROM A,B,WHERE a = b AND c <> b,c, .这就像 ORDER_BY被忽略,并添加 DESC值导致编译错误:

std::string Query = ((SELECT(), "a", "b", "c"),
(FROM(), "A", "B"),
(WHERE(), "a = b AND c <> b"),
(ORDER_BY(), "a", "c", DESC)); // <-- cannot convert 'ORDER' to 'string'

似乎ORDER值未输入 operator ,特化,但在同一命名空间上添加一个自由运算符修复了编译错误:

std::string operator ,(const std::string &left, const ORDER right)
{
std::string Result(left);
return Result.append(1, ',').append(right == ASC? "ASC": "DESC");
}

但我真的以为Fields &Instruction<SQL_ORDER_BY>::operator ,(const ORDER)会被调用,所以我现在寻求一些建议:

  1. 为什么 Instruction<SQL_ORDER_BY>特化模板后,实例未附加到查询字符串?
  2. 为什么 ORDER值不调用 Fields &operator ,(const ORDER)由专业提供。
  3. 有多少 operator ,Instruction<SQL_ORDER_BY>实例?

PS:所有这些努力都是为了自学,此代码的几乎零行将最终出现在生产代码中,因此请避免评论使用库或代码的实用性,

谢谢。

编辑:

有人删除了他的答案,建议添加 using Fields::operator std::string;using Fields::operator,;行到特化,这样做修复了忽略ORDER_BY 问题。

最佳答案

问题是由于您对 , 的过载造成的Instruction<SQL_ORDER_BY> 中的运算符Fields 的子类隐藏父类(super class)中的重载运算符。这正是 C++ 中函数调用解析的工作方式:名称查找首先发生,一旦找到某个 namespace 中的一组名称​​ 就停止;然后,执行重载决议。

问题在 this related article by Herb Sutter 中解释。 .这篇文章与您的问题并不完全相关,但包含解决方案。特别是,请查看“示例 2a”。

你必须使用 using指令导入 Field基类的运算符重载到派生类的范围内,所以你重载了 ,Instruction<SQL_ORDER_BY>不会隐藏它们。

以这个小程序为例:

#include <iostream>
#include <string>

using namespace std;

struct A // Class A contains two overloads of operator ,
{
void operator , (int) { cout << "A::operator , (int)" << endl; }
void operator , (string) { cout << "A::operator , (string)" << endl; }
};

struct B : A // Class B contains only *one* overload of operator ,
// Overloads coming from `A` are *hidden* by this one
{
void operator , (double) { cout << "B::operator , (double)" << endl; }
};

int main()
{
A a;
a, 1; // "A::operator , (int)" will be printed to std out
a, "hello"; // "A::operator , (string)" will be printed to std out

B b;
b, 3.0; // "B::operator , (double)" will be printed to the std out
b, "hello"; // Nothing in the standard output!
}

但是,如果您更改 B 的定义这样:

struct B : A
{
using A::operator ,; // <-- Brings A's overloads into scope!
void operator , (double) { cout << "B::operator , (double)" << endl; }
};

你会看到 main() 的最后一行在上面的示例程序中会将其打印到标准输出:

A::operator , (string)

这意味着 B , 的重载运算符不再隐藏 A 中定义的重载,这很可能是您想要的。

更新:

还有一个问题,答案还没有涵盖。 , 的过载基类中的运算符 Fields返回对 Fields 类型对象的引用.自 ,运算符关联到左侧,表达式 e1, e2, e3被评估为 (e1, e2), e3 .在您的具体情况下,(e1, e2) 的结果是对不支持 , 重载的基类的引用派生类支持的运算符。

让我们再次将其简化为反射(reflect)您的设计的更简单示例:

#include <iostream>
#include <string>

using namespace std;

struct A
{
// Operator overloads return a reference to A
A& operator , (int)
{ cout << "A::operator , (int)" << endl; return *this; }

A& operator , (string)
{ cout << "A::operator , (string)" << endl; *this; }
};

struct B : A
{
// Imported overloads still return a reference to A
using A::operator ,;

// This overload returns a reference to B
B& operator , (double)
{ cout << "B::operator , (double)" << endl; return *this; }
};

int main()
{
B b;
b, 3.0;
b, "hello", 3.2; // What will be displayed here?
}

考虑示例的最后一行。您可能希望它调用 B::operator , (double) , 但这是打印到标准输出的内容:

A::operator , (int)

为什么?好吧,因为逗号运算符的关联性和重载的返回类型。首先,表达式 b, "hello"被评估,并返回一个 A 的引用 。然后,根据这个表达式的结果,函数 A::operator , (3.2)将被调用。 A有一个可行的功能,即接受 int 的功能.然后那个被选中。 B因为第一个表达式的结果 b, "hello" 没有看到重载类型为 A& .

那么怎么解决呢?您可以使用称为 CRTP(“Curiously Recurring Template Pattern”)的设计模式并转换 A 的定义和 B进入以下内容:

template<typename T>
struct A
{
T& operator , (int)
{ cout << "A::operator , (int)" << endl; return *(static_cast<T*>(this)); }

T& operator , (string)
{ cout << "A::operator , (string)" << endl; *(static_cast<T*>(this)); }
};

struct B : A<B>
{
using A::operator ,;
B& operator , (double)
{ cout << "B::operator , (double)" << endl; return *this; }
};

这样,main() 的最后一行上面示例中的函数将打印您期望的标准输出:

A::operator , (string)
B::operator , (double)

关于c++ - 在专用模板中添加运算符重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14564945/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com