簡體   English   中英

通用參考函數模板無法更改的 C++ 重載解析

[英]C++ Overload resolution with universal reference function template which can't be changed

假設我代碼中的某個地方是一個帶有通用引用參數的函數foo我無法更改它

template<typename T>
auto foo(T&& t) { std::cout<<"general version"<<std::endl; }

現在我想為給定的類A重載foo ,並確保為A的任何限定符和引用類型調用重載。 為此,我可以強力地為所有可能的限定條件提供過載(暫時忽略volatile ):

auto foo(A & a) { std::cout<<"A&"<<std::endl; }
auto foo(A const& a) { std::cout<<"A const&"<<std::endl; }
auto foo(A && a) { std::cout<<"A &&"<<std::endl; }
auto foo(A const&& a) { std::cout<<"A const&&"<<std::endl; }

演示 然而,這對於更多參數來說非常糟糕

或者,我可以通過值傳遞,這似乎也捕獲了以前的所有情況:

auto foo(A a) { std::cout<<"A"<<std::endl; }

演示 但是現在需要復制大對象(至少在原則上)。

有沒有優雅的方法來解決這些問題?

請記住,我無法更改通用引用函數,因此SFINAE之類的可能性不大。

C++20 更新:下面的答案對於 C++11 到 C++17 仍然是正確的,但在 C++20 中你可以這樣做:

template <typename T>
    requires std::same_as<std::remove_cvref_t<T>, A>
auto foo(T&& t) {
    // since this is more constrained than the generic forwarding reference
    // this one should be preferred for foo(A{})
}

您可以通過創建命名概念來使用更方便的語法:

template <typename T, typename U>
concept DecaysTo = std::same_as<std::decay_t<U>, T>;

// longest form
template <typename T> requires DecaysTo<T, A> void foo(T&&);

// middle form
template <DecaysTo<A> T> void foo(T&&);

// abbreviated form
void foo(DecaysTo<A> auto&&);

老實說,我認為你在這里倒霉了。 典型的方法都失敗了。 你可以做...

SFINAE?

template <typename T> auto foo(T&& );
template <typename T,
          typename = only_if_is<T, A>>
auto foo(T&& );

foo(A{}); // error: ambiguous

編寫一個接受左值或右值引用的類?

template <typename T> lref_or_ref { ... };
    
template <typename T> auto foo(T&& );
auto foo(lref_or_ref<A> );

foo(A{}); // calls general, it's a better match

您能做的最好的事情是使用選擇器引入轉發功能:

template <int I> struct chooser : chooser<I - 1> { };
template <> struct chooser<0> { };

template <typename T>
auto bar(T&& t, chooser<0> ) {
    // worst-option, general case
    foo(std::forward<T>(t));
}

template <typename T,
          typename = only_if_is<T, A>>
auto bar(T&& t, chooser<1>) {
    // A-specific
}

template <typename T>
auto bar(T&& t) {
    bar(std::forward<T>(t), chooser<20>{});
}

但是您在評論中提到這對您也不起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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