Почему шаблоны не могут принимать локальные типы функций? - PullRequest
6 голосов
/ 12 августа 2010

В C ++ нормально иметь функцию, которая принимает локальный тип функции:

int main() {
  struct S { static void M(const S& s) { } };
  S s;
  S::M(s);
}

, но не хорошо иметь шаблон, который имеет:

template<typename T> void Foo(const T& t) { }

int main() {
  struct S { } s;
  Foo(s);   // Line 5: error: no matching function for call to 'Foo(main()::S&)'
}

14.3.1 параграф 2 в стандарте c ++.

Тип без связи [...] не должен использоваться в качестве аргумента шаблона для параметра типа шаблона

Почему C ++ запрещает это?


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


ps Пожалуйста, не говорите просто ", это не разрешено, потому что стандарт говорит, что это не "

Ответы [ 2 ]

7 голосов
/ 12 августа 2010

Я полагаю, что предвиденная трудность заключалась в том, что два экземпляра Foo<T> фактически означали совершенно разные вещи, потому что T не было одинаковым для обоих.Несколько ранних реализаций шаблонов (включая cfront) использовали репозиторий экземпляров шаблонов, поэтому компилятор мог автоматически создавать экземпляр шаблона над требуемым типом, когда / если было обнаружено, что экземпляр этого типа еще не был в репозитории.

Чтобы это работало с локальными типами, хранилище не просто могло бы хранить тип, для которого был создан экземпляр шаблона, но вместо этого ему нужно было бы сделать что-то вроде создания полного «пути» квведите для экземпляра.Хотя это, вероятно, возможно, я думаю, что это было воспринято как большая дополнительная работа для небольшой (если вообще есть) реальной выгоды.

С тех пор правила изменились настолько, что компилятору уже требуется делать что-то,об эквивалентных, нахождении (и объединении) экземпляров одного и того же типа в разных местах (в том числе в разных TU), чтобы два экземпляра foo<int> (например) не нарушали ODR.Исходя из этой реализации, ограничение было ослаблено в (текущем наброске) C ++ 0x (вы все еще не можете создать экземпляр класса шаблона для локального типа, но вы можете использовать локальный тип в качестве параметра для функции шаблона).

3 голосов
/ 12 августа 2010

Я предполагаю, что это потому, что это потребовало бы эффективного создания шаблона в рамках функции, поскольку именно там такие типы видны.Однако в то же время предполагается, что экземпляры шаблона действуют так, как если бы они находились в области действия, в которой определен шаблон.Я уверен, что с этим можно как-то справиться, но если я прав, орган по стандартизации решил не возлагать этого бремени на разработчиков компиляторов.

Подобное решение было причиной vector<vector<int>> неверного синтаксисапо стандарту;обнаружение этой конструкции требует некоторого взаимодействия между лексером компилятора и фазами парсера.Однако это меняется, потому что специалисты по стандартам C ++ 0x обнаружили, что все компиляторы все равно обнаруживают его, чтобы выдавать вменяемые сообщения об ошибках.

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

...