LINUX.ORG.RU

Такое вообще легально?

 ,


0

2

Есть шаблонная декларация с возвращаемым типом auto и без «trailing return type». GCC и Clang едят. Такое вообще легально?

Код:

foo.h

#pragma once

#include <string>
#include <utility>

class Foo {
public:
  explicit Foo(std::string name) : _name{std::move(name)} {}

  void bar() const;

private:
  template <typename Callback>
  auto wrap(Callback&& c) const; // <-- !!!
  
  const std::string _name;
};

foo.cpp

#include "foo.h"

#include <iostream>

template <typename Callback>
auto Foo::wrap(Callback&& c) const {
  return [&]() {
    std::cout << "das ist ein Wrapper aus " << _name << '\n';
    c();
  };
}

void Foo::bar() const {
  auto f = wrap([]() { std::cout << "das is ein Lambda\n"; });
  f();
}

main.cpp

#include "foo.h"

int main() {
  Foo foo{"Foo #1"};
  foo.bar();
}

Выводит (как и задумывалось):

das ist ein Wrapper aus Foo #1
das is ein Lambda

GCC: https://wandbox.org/permlink/jXIrkG0U13I9ZRnP
Clang: https://wandbox.org/permlink/6hs2OoxNpzhnu9iX

Попробуй положить реализации wrap и bar в разные единицы трансляции. Или даже проще - поменяй местами: сперва реализация bar, потом wrap

anonymous ()

Похоже на то (dcl.spec.auto):

The placeholder type can appear with a function declarator in the decl-specifier-seq, type-specifier-seq, conversion-function-id, or trailing-return-type, in any context where such a declarator is valid. If the function declarator includes a trailing-return-type ([dcl.fct]), that trailing-return-type specifies the declared return type of the function. Otherwise, the function declarator shall declare a function. If the declared return type of the function contains a placeholder type, the return type of the function is deduced from non-discarded return statements, if any, in the body of the function ([stmt.if]).

Ниже есть примеры. Из ограничений видно, что функция не должна быть виртуальной и будущие объявления не должны уточнять тип. А так, видимо, разрешено.

xaizek ★★★★★ ()
Ответ на: комментарий от deterok

Т.к. оно разруливается на этапе конпеляции, то, скорее нет. Но зачем писать так, когда можно написать «по сишному» и точно указать что там возвращается? Оно еще и на любом утюге собираться будет, в отличии от.

deep-purple ★★★★★ ()
Ответ на: комментарий от deep-purple

Я имел в виду ответ на вопрос «почему бы вам на пхп не писать?». Если бы пхп компилировался и скомпилированный файл работал со скоростью реализации на C++, 90% программистов с C++ перешли бы на него.

monk ★★★★★ ()
Ответ на: комментарий от deep-purple

Но зачем писать так, когда можно написать «по сишному» и точно указать что там возвращается?

Вместо

auto Foo::wrap(Callback&& c)
писать
void (*Foo::wrap(Callback&& c))(void)
?

Вы уверены, что это читаемее?

monk ★★★★★ ()
Последнее исправление: monk (всего исправлений: 2)
Ответ на: комментарий от deep-purple

Но зачем писать так, когда можно написать «по сишному» и точно указать что там возвращается?

Суть в том, что там лямбда возвращается. А ее тип явно указать нельзя. Разве что в std::function обернуть.

У меня в реальном коде возвращается шаблонный Visitor который наследуется от лямбд (из моей соседней темы). Там уже никак не завернешь, ибо operator() перегружен.

KennyMinigun ★★★★★ ()
Последнее исправление: KennyMinigun (всего исправлений: 1)
Ответ на: комментарий от deep-purple

Но зачем писать так, когда можно написать «по сишному» и точно указать что там возвращается?

Ну напишите wrap без использования auto, дело-то. Казалось бы.

Но есть ощущение, что у вас не получится. Или получится?

eao197 ★★★★★ ()
Ответ на: комментарий от anonymous

Тем же, чем лямбды лучше функций. Они определены по месту, а не парой экранов выше. При чтении псевдоним будет давать почти столько же информации, сколько и auto, но при записи придётся его отдельно записывать.

monk ★★★★★ ()