2016-11-04 5 views
11

В чем разница между decltype(auto) и decltype(returning expression) как возвращаемый тип функции (шаблон), если expr используется без круглых скобок в обоих случаях?В чем разница между decltype (auto) и decltype (return expr) как возвращаемый тип?

auto f() -> decltype(auto) { return expr; } // 1 
auto f() -> decltype(expr) { return expr; } // 2 

Над f могут быть определены/объявлены в любом контексте и может быть либо функцией (член) или (член) шаблон функции, или даже (всего) лямбда. expr может зависеть от любых параметров шаблона.

Во второй версии оба expr являются точно такими же выражениями без дополнительных круглых скобок.

Какие различия можно ожидать, используя первую или вторую форму в C++ 14 и более поздних версиях?

Что делать, если круглые скобки используются повсюду?

ответ

11

Да, есть разница. Первый будет определять тип возврата на основе выражения return в теле функции.

Второй не будет также устанавливать тип возврата в тип выражения внутри decltype(), но также будет применяться выражение sfinae. Это означает, что если выражение внутри decltype недопустимо, компилятор будет искать другую действительную перегрузку. В то время как первая версия будет жесткой ошибкой.

Возьмем такой пример:

template<typename T> 
auto fun(T a) -> decltype(a.f()) { return a.f(); } 

template<typename T> 
auto fun(T a) -> decltype(a.g()) { return a.g(); } 

struct SomeType { 
    int g() { return 0; } 
}; 

fun(SomeType{}); 

Это выбрать правильную перегрузку. Теперь, если мы заменим decltype(expr) на decltype(auto), компилятор не сможет выбрать правильную перегрузку, так как нет ничего в сигнатуре функции, которая сдерживает то, что тип должен делать.

6

decltype(auto) используется для

  • Forward типа возврата в общем коде, вы не хотите, чтобы напечатать много дублей вещи

    template<class Func, class... Args> 
    decltype(auto) foo(Func f, Args&&... args) 
    { 
        return f(std::forward<Args>(args)...); 
    } 
    
  • Задержка типа вычета, как вы можете видеть в this question, у компиляторов возникли проблемы с decltype(auto)

    • Это не работает, как вы можете видеть g++ и clang++

      template<int i> struct Int {}; 
      constexpr auto iter(Int<0>) -> Int<0>; 
      
      template<int i> constexpr auto iter(Int<i>) -> decltype(iter(Int<i-1>{})); 
      
      int main(){ 
          decltype(iter(Int<10>{})) a; 
      } 
      
    • Это хорошо работает, как вы можете видеть here:

      template<int i> struct Int {}; 
      
      constexpr auto iter(Int<0>) -> Int<0>; 
      
      template<int i> 
      constexpr auto iter(Int<i>) -> decltype(auto) { 
          return iter(Int<i-1>{}); 
      } 
      
      int main(){ 
          decltype(iter(Int<10>{})) a; 
      } 
      

decltype(expr):

  • применяет SFINAE, а decltype(auto) не является
3

Еще один пример. В случае decltype(auto) допускается использование лямбда. В случае decltype(expr) лямбды запрещены.

Это потому, что а) лямбды не допускается в качестве невычисленных операндов (например, в sizeof или decltype) и б) вид в decltype и в теле двух выражений будет отличаться, так как они являются два отдельными выражениями лямбды

// ill-formed: lambda within decltype 
auto f() -> decltype([]{}) { return []{}; }; 

// allowed: lambda is not in decltype, and only appears once 
auto f() -> decltype(auto) { return []{}; } 
+0

'auto f() -> decltype ([] {}) {return {}; } 'будет работать? – Orient

+0

@Orient nopes, извините –

+0

Как вы думаете, проблема [this] (https://llvm.org/bugs/show_bug.cgi?id=23141) как-то связана с этим вопросом? – Orient

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