6

Пусть где-то в моем коде есть функция foo с универсальным опорным параметром, который я не могу изменить:разрешение C++ Перегрузка с универсальным шаблоном опорной функции, которые не могут быть изменены

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

Теперь я хочу перегрузите foo для данного класса A и убедитесь, что для любого классификатора и ссылочного типа A вызывается перегрузка. Для этого я могу отладочный forcely обеспечить перегрузку для всех возможных квалификации (игнорировать 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; } 

Demo. Это, однако, весит очень плохо для получения дополнительных параметров.

С другой стороны, я могу передать по значению, которое, кажется, чтобы захватить, а все предыдущие случаи:

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

Demo. Теперь нужно скопировать большой объект (по крайней мере в принципе).

Есть ли элегантный способ решения этих проблем?

Помните, что я не могу изменить универсальную опорную функцию, поэтому SFINAE и тому подобное не имеют возможности.

+0

пишет функцию обертки, которая перенаправляет аргументы правильной функции и с помощью этого вместо разумного решения для вас? – TartanLlama

+0

AFAIK компилятор всегда ищет наиболее подходящий вариант. Что делать, если вы добавили enable_if > в "перегрузку"? –

+1

@TartanLlama: не совсем. В коде соответствующая функция - 'operator &&' (я просто взял 'foo' в качестве простого примера). Это библиотека, и это слишком ошибочно. – davidhigh

ответ

7

Честно говоря, я думаю, вам здесь не повезло. Типичные подходы все терпят неудачу. Вы можете ...

SFINAE?

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

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

Создать класс, который использует ссылку l-or-rvalue?

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 

Лучшее, что вы можете сделать, это ввести функцию переадресации с помощью Chooser:

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>{}); 
} 

Но вы упомянули in a comment, что это не работает для вас тоже. Поэтому, я думаю, ваш вариант: написать предложение в комитет по стандартам!


Икатно, есть надежда! Если понятия получают принимаются (хороший пункт, TartanLlama!):

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

Возможно получить хотя бы lvalues ​​с шаблоном auto foo (T & t); ', но, похоже, для rvalues ​​этот способ не подходит. Если вы не используете понятия, то есть (где вы можете определить чистый выводный ссылочный параметр rvalue), но тогда вы можете использовать более легкое решение для получения как с помощью принудительной ссылки ref. – dyp

Смежные вопросы