Я экспериментировал с системой для составных конвейеров, которая включает в себя набор «этапов», которые могут быть шаблонными.Каждый этап обрабатывает свою собственную настройку, выполнение и очистку, а вычитание шаблона используется для построения минимального списка «состояний», используемых конвейером.Это требует довольно большого количества шаблонного кода шаблона, который показал некоторое явно несоответствующее поведение.Несмотря на успешные эксперименты, фактическое внедрение его в нашу кодовую базу привело к ошибкам из-за недопустимых экземпляров.
Потребовалось некоторое время, чтобы отследить разницу между игрушечным (рабочим) решением и более богатой версией, нов конце концов, оно было сужено до явной спецификации пространства имен.
template<typename KeyType = bool>
struct bind_stage
{
static_assert(!std::is_same<KeyType, bool>::value, "Nope, someone default instantiated me");
};
template<typename BoundStage, typename DefaultStage>
struct test_binding {};
template<template<typename...>class StageTemplate, typename S, typename T>
struct test_binding <StageTemplate<S>, StageTemplate<T>> {};
template<typename T>
auto empty_function(T b) {}
Тогда наш главный:
int main()
{
auto binder = test_binding<bind_stage<int>, bind_stage<>>();
//empty_function(binder); // Fails to compile
::empty_function(binder); // Compiles happily
return 0;
}
Теперь я не уверен, ожидаю ли я неудачу или нет.С одной стороны, мы создаем test_binder<bind_stage<int>,bind_stage<bool>>
, который, очевидно, включает недопустимую реализацию bind_stage<bool>
как часть определения его типа.Который не должен компилироваться.
С другой стороны, он включен исключительно как имя, а не как определение.В этой ситуации это может быть просто объявленный заранее шаблон, и мы ожидаем, что он будет работать до тех пор, пока во внешнем шаблоне на самом деле ничего не ссылается на него.
Чего я не ожидал, так это двух разных вариантов поведения в зависимостио том, добавил ли я (теоретически лишний) глобальный спецификатор пространства имен.
Я пробовал этот код в Visual Studio, Clang и GCC.У всех одинаковое поведение, что заставляет меня отказаться от этой ошибки компилятора.Объясняется ли это поведение чем-то в стандарте C ++?
РЕДАКТИРОВАТЬ: Еще один пример от Даниэля Лэнгра, который для меня менее важен:
template <typename T>
struct X {
static_assert(sizeof(T) == 1, "Why doesn't this happen in both cases?");
};
template <typename T>
struct Y { };
template <typename T>
void f(T) { }
int main() {
auto y = Y<X<int>>{};
// f(y); // triggers static assertion
::f(y); // does not
}
Либо X<int>
создается в то время какопределение Y<X<int>>
или это не так.Какое отношение имеет использование функции в неопределенной области видимости к чему-либо?