[英]Function template argument deduction with user-defined conversion operator
假設我有一個包裝字符串文字的 class :
template <size_t N>
class literal {
public:
constexpr literal(const char(&s)[N+1]) : wrapped_(s) {}
constexpr const char * c_str() const { return wrapped_; }
constexpr size_t size() const { return N; }
private:
const char (&wrapped_)[N+1];
};
template <size_t N>
literal<N-1> make_literal(const char (&s)[N]) { return literal<N-1>(s); }
現在,我希望這種包裝字符串類型的實例可以隱式轉換回const char[N]
,在某種程度上我仍然可以訪問它的大小。 我希望能夠做類似的事情:
template <size_t N>
void foo(const char(&s)[N]) {
std::cout << N << ": " << s << std::endl;
}
int main() {
constexpr auto s = make_literal("testing");
foo(s);
}
我的目標是為foo()
定義一個 function ,它可以接受實際的字符串文字以及包裝的文字。 我嘗試將用戶定義的轉換運算符添加到 class 定義中:
using arr_t = char[N+1];
constexpr operator const arr_t&() const { return wrapped_; }
但這給了我以下 clang :
候選模板被忽略:無法將 'const char [N]' 與 'const literal<7>' 匹配
如果我將對foo()
的調用更改為以下內容,它將起作用:
foo((const char(&)[8])s);
...這意味着轉換運算符有效,但不是在模板參數推導的上下文中。 有沒有什么辦法可以在不專門定義foo()
來獲取包裝文字的情況下完成這項工作?
您遇到的問題是模板從不轉換參數。 既然你給它一個const literal<7>
,這就是它必須使用的全部。
解決這個問題的簡單方法是添加一個重載,然后在重載中進行強制轉換以調用您的字符串文字版本。 那應該看起來像
template <size_t N>
void foo(const literal<N> &lit) {
foo(static_cast<typename literal<N>::arr_t&>(lit)); // explicitly cast to the array type alias
}
這給了你一個完整的例子
template <size_t N>
class literal {
public:
constexpr literal(const char(&s)[N+1]) : wrapped_(s) {}
constexpr const char * c_str() const { return wrapped_; }
constexpr size_t size() const { return N; }
using arr_t = const char[N+1]; // <- Add const here since literals are const char[N]
constexpr operator const arr_t&() const { return wrapped_; }
private:
const char (&wrapped_)[N+1];
};
template <size_t N>
constexpr literal<N-1> make_literal(const char (&s)[N]) { return literal<N-1>(s); }
template <size_t N>
void foo(const char(&s)[N]) {
std::cout << N << ": " << s << std::endl;
}
template <size_t N>
void foo(const literal<N> &lit) {
foo(static_cast<typename literal<N>::arr_t&>(lit)); // explicitly cast to the array type alias
}
int main() {
constexpr auto s = make_literal("testing");
foo(s);
}
是的,您正在添加重載,但不必復制所有重要代碼。
如果您可以使用 C++17 並且您不介意一點間接性,您可以使用一個 function 使用std::string_view
並使用operator std::string_view
提供literal
來完成所有這些。 那看起來像
template <size_t N>
class literal {
public:
constexpr literal(const char(&s)[N+1]) : wrapped_(s) {}
constexpr const char * c_str() const { return wrapped_; }
constexpr size_t size() const { return N; }
using arr_t = const char[N+1];
constexpr operator std::string_view() const { return wrapped_; }
private:
const char (&wrapped_)[N+1];
};
template <size_t N>
constexpr literal<N-1> make_literal(const char (&s)[N]) { return literal<N-1>(s); }
void foo(std::string_view s) {
std::cout << s.size() << ": " << s << std::endl;
}
int main() {
constexpr auto s = make_literal("testing");
foo(s);
foo("testing");
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.