Отдельное определение и объявление функции-члена шаблона с помощью enable_if, параметр шаблона которого также включает функцию-член constexpr

Следующее не компилируется под g ++ 8.1.0 на CentOS 7:

hey.h

#pragma once
#include <iostream>
#include <type_traits>

class Valid {};
class Invalid {};

struct Hey
{
template<typename T>
static constexpr bool is_valid() { return std::is_same_v<T, Valid>; }

template<typename T, std::enable_if_t<is_valid<T>()>* = nullptr>
void howdy() const;
};

template<typename T, std::enable_if_t<Hey::is_valid<T>()>*>
void Hey::howdy() const
{
std::cout << "Howdy" << std::endl;
}

Выход компилятора:

In file included from hey.cpp:1:
hey.h:18:8: error: no declaration matches ‘void Hey::howdy() const’
void Hey::howdy() const
^~~
hey.h:14:10: note: candidate is: ‘template<class T, std::enable_if_t<is_valid<T>()>* <anonymous> > void Hey::howdy() const’
void howdy() const;
^~~~~
hey.h:8:8: note: ‘struct Hey’ defined here
struct Hey
^~~

Удивительно, но все, что мне нужно сделать, чтобы правильно скомпилировать и получить желаемое поведение, это добавить typedef в Hey:

hey.h (исправлено, первые скучные строки пропущены)

struct Hey
{
template<typename T>
static constexpr bool is_valid() { return std::is_same_v<T, Valid>; }

template<typename T>
using EnableType = std::enable_if_t<is_valid<T>()>;

template<typename T, EnableType<T>* = nullptr>
void howdy() const;
};

template<typename T, Hey::EnableType<T>*>
void Hey::howdy() const
{
std::cout << "Howdy" << std::endl;
}

hey.cpp

#include "hey.h"
int main(int, char**)
{
Hey hey;
hey.howdy<Valid>();

// Adding this line breaks the build, as it should:
// hey.howdy<Invalid>();

return 0;
}

После многих настроек я сузил ситуацию с ошибкой компилятора до того, что 1) is_valid() является членом Hey и 2) howdy() объявлен внутри HeyТело, но определено снаружи. Если вы удалите using и сделать is_valid() автономная функция вне HeyНет проблем с компиляцией. Если вы удалите using и определить howdy() внутри определения класса также нет проблем с компиляцией. Но когда howdy() определяется вне определения класса, is_valid() объявляется внутри определения класса, а using нет, компилятор выходит из строя. Это правильное поведение? Я смотрю на ошибку компилятора?

3

Решение

Соответствие выражений в объявлениях шаблона основано на эквивалентность, концепция, основанная на правиле одного определения. Чтобы два выражения считались эквивалентными, они должны быть идентичны токену по токену по модулю переименования параметров шаблона.

Выражения is_valid<T>() а также Hey::is_valid<T>() не эквивалентны (у второго есть два токена, у первого нет), поэтому компилятору не требуется их сопоставлять.

Hey::EnableType<T> является типом и не подчиняется строгим правилам эквивалентности выражений.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]