簡體   English   中英

Function 模板參數推導與用戶定義的轉換運算符

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM