std :: function, литеральные типы и шаблоны - PullRequest
3 голосов
/ 26 июня 2019

Я работаю над проектом C ++ 17, который, помимо прочего, имеет следующие определения (в моем пространстве имен, конечно):

using CppFunction = std::function<int(StatePtr&)>;

template<typename T>
using CppMethod = std::function<int(T*, StatePtr&)>;

Теперь я объявляю некоторые функции:

template<typename... Targs, typename F>
constexpr CppFunction CppFunctionNative(F func);

template<typename... Targs, typename F, typename T = (deducing class from F here) >
constexpr CppMethod<T> CppMethodNative(F func);

К моему удивлению, первое объявление вызывает ошибку компилятора Constexpr function's return type is not a literal type, но второе работает просто отлично.

Почему это происходит? Связано ли это с тем, что тип возвращаемой функции - шаблон?

UPD: упрощенный автономный пример:

#include <functional>

using CppFunction = std::function<int(int&)>;

template<typename T>
using CppMethod = std::function<int(T*, int&)>;

// Clang will complain
template<typename F>
constexpr CppFunction CppFunctionNative(F func) {};

// Clang will not complain
template<typename F, typename T = /*(deducing class from F here)*/char >
constexpr CppMethod<T> CppMethodNative(F func) {};

// main() function doesn't matter
int main() {
    CppFunctionNative(0);
    CppMethodNative(0);
    return 0;
};

Интересно, что OnlineGDB и автономный GCC 8.3.0 не жалуются на это, но мой Clang 8 делает.

Ответы [ 2 ]

7 голосов
/ 26 июня 2019

К моему удивлению, первое объявление вызывает ошибку компилятора. Возвращаемый тип функции Constexpr не является литеральным, но второе работает просто отлично.

Почему это происходит? Связано ли это с тем, что тип возвращаемой функции - шаблон?

Да. В первом случае компилятор может доказать, что эта конкретная специализация std::function не является литеральным типом.

Во втором случае он должен знать T, прежде чем узнает, является ли конкретная специализация std::function литеральным типом.

template<class T>
struct example {
  virtual T get() const {return {};}
  ~example() {}
};
template<>
struct example<int> {};

#if 0
template<class F>
constexpr example<double> test( F ) { return {}; }
#endif

template<class T, class F>
constexpr example<T> test2( F ) { return {}; }

Живой пример

test незаконно; test2 в порядке. На самом деле, test2<int>( 3.14 ) является законным constexpr вызовом.

Теперь у std::function нет такой специализации , но компилятор не обязан доказывать это; в общем случае это требует решения проблемы остановки, что стандарт C ++ старается избегать от компиляторов.

Как уже упоминалось @MaxLanghof, такого рода ошибки приводят к "неправильной, не требующей диагностики" программе. Компилятор не обязан обнаруживать, что ваша constexpr функция не может быть constexpr, но если вы сделаете это, компилятор может делать все что угодно, в том числе генерировать сообщение об ошибке (или что-то еще хуже).

Таким образом, GCC не ошибается, чтобы пропустить ошибку, и clang не ошибается, чтобы выдать ошибку. Излучение ошибок Кланга в некотором смысле является более высоким QoI, чем пропуск GCC.

2 голосов
/ 26 июня 2019

Редактировать: ответ Якка является более полным - нужно, конечно, рассмотреть теоретическую возможность std::function специализаций!

constexpr означает "существует по крайней мере один набораргументы, для которых эта функция выдает постоянное выражение ".Если таких аргументов не существует, программа некорректна, диагностика не требуется .Это значит, что компилятору решать, полностью ли он игнорирует эту проблему, жалуется ли он только во время создания экземпляра или уже лает на объявление.

clang, очевидно, достаточно умный / энергичный чтобы понять, что шаблон функции с не-литеральным типом возврата никогда не может быть constexpr.gcc, похоже, не стоит проверять это - это не обязательно.Ваша программа по-прежнему неверна - std::function не является литеральным типом и поэтому никогда не может быть возвращен функцией constexpr.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...