2010-08-12 3 views
6

В C++ это нормально, чтобы иметь funcction, который принимает локальный тип функции:Почему шаблоны не могут использовать локальные типы?

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 paragraph 2 in the c++ standard.

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

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


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


p.s. Пожалуйста, не просто скажите «thats not allowed because the standard says it's not»

+5

Нет веской причины, и C++ 0x удалит это ограничение (но не тот, который связан с p.s; я до сих пор не знаю, почему это недопустимо). –

+0

@Mike; Короче и точно! – BCS

ответ

3

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

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

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

+1

«Когда-нибудь» будет, как только C++ 0x будет ратифицирован, если они не передумают. Окончательный проект снимает это ограничение. –

+0

Я мог бы представить архитектуру компилятора, где было бы трудно реализовать, но я также могу думать о тех, где это было бы бесплатно. – BCS

7

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

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

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

+0

Короче говоря, это было больше работы для компилятора? – BCS

+0

@BCS: Хотя это, вероятно, так и верно, это не так много *, что раньше он работал больше для компилятора, поскольку 1) большая часть дополнительной работы в настоящее время выполняется по другим причинам, и 2) компиляция C++ теперь настолько сложна, что люди более склонны принимать добавление еще большей сложности, если она не слишком радикальна. –

+0

§14.3.1 [temp.arg.type] имеет несколько примеров передачи локальных типов в шаблон класса. – Potatoswatter

Смежные вопросы