2016-09-28 1 views
5

Рассмотрим следующий код:decltype (auto), возвращающий тип возврата и sfinae: можем ли мы их смешивать?

auto f() -> decltype(auto) { /* do whatever you want here */ } 
int main() { f(); } 

Возвращаемый тип выводится и decltype(auto) используется как отстающие тип возвращаемого значения.
Код ниже немного изменен (на самом деле, sfinae'd) версия:

struct S { static void f() {} }; 
struct T {}; 

template<typename U> 
auto f(int) -> decltype(U::f(), void()) { 
    // do whatever you want here 
} 

template<typename> 
auto f(char) -> decltype(auto) { 
    // do whatever you want here 
} 

int main() { 
    f<S>(0); 
    f<T>(0); 
} 

Если взять экзамен эту функцию:

template<typename U> 
auto f(int) -> decltype(U::f(), void()) { 
    // do whatever you want here 
} 

Возникает вопрос: можно ли используйте возвращаемый тип возврата, чтобы сделать sfinae и все еще иметь тип возвращаемого вывода?
Я имею в виду что-то вроде кода ниже (который не работает, конечно):

template<typename U> 
auto f(int) -> decltype(U::f(), auto) { 
    // do whatever you want here 
} 

Примечания: Я не ищу альтернативные подходы, включающие параметры шаблона, я знаю их, и я» m просто интересно узнать, является ли жизнеспособным решением.

+1

Не думайте, что это возможно, но вы хотите, чтобы тип был выведен как 'auto' или как' decltype (auto) '? – Holt

+0

Не думайте, что вы можете здесь что-то сделать. Выведенные типы возврата намеренно не являются SFINAE. – Xeo

+0

@Holt Хороший вопрос, я бы сказал 'decltype (auto)' как в первом примере, но если вы знаете, как его вывести как 'auto', это может быть хорошим ответом. – skypjack

ответ

4

decltype(auto) - неотъемлемая конструкция (почти как если бы это было ключевое слово, как decltype_auto). Помимо этого, auto не может использоваться как автономный объект внутри decltype(x), поскольку это предотвратит действительное выражение x.

0

Не ответ, но возможное обходное решение с использованием void_t.

По крайней мере, это так DRY, как то, что вы хотите сделать:

template<typename... Ts> struct make_void { typedef void type;}; 
template<typename... Ts> using void_t = typename make_void<Ts...>::type; 


struct S { static int f() { return 3; } }; 
struct P { static int p() { return 4; } }; 
struct T {}; 

template<typename U, void_t<decltype(U::f())>* = nullptr > 
auto f(int) -> decltype(auto) 
{ 
    // do whatever you want here 
    std::cout << "f1\n"; 
    return U::f(); 
} 

template<typename U, void_t<decltype(U::p())>* = nullptr > 
auto f(int) -> decltype(auto) 
{ 
    // do whatever you want here 
    std::cout << "f3\n"; 
    return U::p(); 
} 

template<typename> 
auto f(char) -> decltype(auto) { 
    std::cout << "f2\n"; 
    // do whatever you want here 
} 

int main() { 
    std::cout << f<S>(0) << '\n'; 
    std::cout << f<P>(0) << '\n'; 
    f<T>(0); 
} 
0

Вы можете добавить еще один параметр типа void(*)() функции и назначить лямбда с задним типом возврата к нему в качестве аргумента по умолчанию так SFINAE могут быть применены через лямбда:

template<typename U> 
decltype(auto) f(int, void(*)() = []()->decltype(U::f(), void()) {}) 
{ 
    // do whatever you want here 
} 
Смежные вопросы