背景:
我正在研究一种查询DSL,它将解析==
,<
等表达式,并通过运算符重载返回过滤器对象。
问题:
与字符串文字一起使用时,我的模板方法失败。我尝试提供同时使用std::string
和char
的模板的特定实例化,但是似乎都不起作用。
代码在下面。导致main中问题的行标有注释。我尝试过的替代解决方案在代码中已注释掉。
可以找到相同代码的可运行副本here。
我确实知道可以用std::string("text")
手动包装字符串文字,但是我希望能够使用纯字符串文字(如果可能的话)。
#include <iostream>
template<typename T>
struct Filter;
struct Field
{
Field(const std::string &val): name(val) { }
Field(std::string &&val): name(std::move(val)) { }
std::string name;
// template <signed N>
// Filter<std::string> operator==(const char (&val) [N]);
template <typename T>
Filter<T> operator==(const T &val);
};
template <typename T>
Filter<T> Field::operator==(const T &val)
{
return Filter<T>{ *this, val, "==" };
}
// template <signed N>
// Filter<std::string> Field::operator==(const char (&val) [N])
// {
// return Filter<std::string>{ *this, std::string(val), "==" };
// }
// template <>
// Filter<std::string> Field::operator==<std::string>(const std::string &val)
// {
// return Filter<std::string>{ *this, val, "==" };
// }
template<typename T>
struct Filter
{
Field f;
T val;
std::string op;
};
int main() {
Field f1 { "field1" };
Field f2 { "field1" };
std::cout << (f1 == 1).val;
std::cout << (f1 == "Hello").val; // <--- the source of my problems
}
答案 0 :(得分:9)
问题是c数组不可复制,所以
Filter<char [6]>{ *this, val, "==" }; // Error
您的重载是正确的,但是Filter
需要在您的operator==
重载之前 重新排序和定义。返回Filter<T>
的重载取决于T
,因此在这种情况下,Filter
的定义可以推迟。但是,当您返回Filter<std::string>
时,编译器需要预先实际定义Filter
。
#include <iostream>
template<typename T>
struct Filter;
struct Field
{
Field(const std::string &val): name(val) { }
Field(std::string &&val): name(std::move(val)) { }
std::string name;
template <std::size_t N> Filter<std::string> operator==(const char (&val) [N]);
template <typename T>
Filter<T> operator==(const T &val);
};
template<typename T>
struct Filter
{
Field f;
T val;
std::string op;
};
template <typename T>
Filter<T> Field::operator==(const T &val)
{
return Filter<T>{ *this, val, "==" };
}
template <std::size_t N>
Filter<std::string> Field::operator==(const char (&val) [N])
{
return Filter<std::string>{ *this, std::string(val), "==" };
}
int main() {
Field f1 { "field1" };
Field f2 { "field1" };
std::cout << (f1 == 1).val;
std::cout << (f1 == "Hello").val;
}
答案 1 :(得分:3)
在Filter
被推导为T
的情况下,您可以做的是char[N]
。添加
template<std::size_t N>
struct Filter<char[N]>
{
Field f;
std::string val;
std::string op;
};
将导致Filter<T>{ *this, val, "==" }
调用上述专业化,它将使用std::string
存储val
。
答案 2 :(得分:2)
由于具有C ++ 17标记,因此还有另一个解决此问题的方法:deduction guides
#include <iostream>
template<typename T>
struct Filter;
struct Field
{
Field(const std::string &val): name(val) { }
Field(std::string &&val): name(std::move(val)) { }
std::string name;
// note the use of auto here
template <typename T>
auto operator==(const T &val);
};
template <typename T>
auto Field::operator==(const T &val)
{
// do not use Filter<T> here, or the deduction guide won't kick in
return Filter{ *this, val, "==" };
}
template<typename T>
struct Filter
{
Field f;
T val;
std::string op;
};
// ------- Deduction Guides -----------
template<typename T>
Filter(Field, T, std::string) -> Filter<T>;
// will tell the compiler to create a Filter<string> with a c-array argument
template<std::size_t N>
Filter(Field, const char(&)[N], std::string) -> Filter<std::string>;
// ------------------------------------
int main() {
Field f1 { "field1" };
Field f2 { "field1" };
std::cout << (f1 == 1).val;
// creates a Filter<string> instead of trying to
// create a Filter<const char(&)[6]> due to the deduction guide
std::cout << (f1 == "Hello").val;
}