Разрешение имени и Точка создания экземпляра в шаблонах - PullRequest
0 голосов
/ 28 сентября 2010

Это утверждение стандарта ISO C ++ 14.6.4.1. Точка создания

 4.If a virtual function is implicitly instantiated, its point of instantiation
   is immediately following the point of instantiation of its enclosing
   class template specialization.

 5.An explicit instantiation directive is an instantiation point for the
   specialization or specializations specified by the explicit 
   instantiation directive.

 6.The instantiation context of an expression that depends on the
   template arguments is the set of declarations with external linkage 
   declared prior to the point of instantiation of the template 
   specialization in the same translation unit.

Я не могу написать программы для всего этого раздела. Я пытаюсь написать программы для этого раздела со вчерашнего дня.

Пожалуйста, обычно я бы попытался задать 1 или более баллов. В любом разделе. Но здесь я не могу понять ни одного пункта в этом разделе.

Итак, любой может предоставить мне код для этих разделов, чтобы понять.

Ответы [ 2 ]

2 голосов
/ 28 сентября 2010

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

Третье утверждение (14.6.4.1/6) говорит нам, в чем заключается точка создания точек: они являются точкой, где имена ищутся во время второй фазы поиска имени. Имена, которые объявлены до точки инстанцирования, видны; те, которые объявлены впоследствии, не являются. (На первом этапе двухфазного поиска имен независимые имена ищутся в наборе объявлений, предшествующих шаблону определение ).

Итак, учитывая:

template <typename T> void foo() {
  T() + T();
}

контексты создания выражения T()+T() - это набор объявлений, которые предшествуют соответствующим точкам реализации foo<T>. Имя operator+ ищется в этих контекстах и ​​включает в себя объявления, которые следуют этому определению, но предшествуют точке создания.

1 голос
/ 28 мая 2016

Кажется, всегда есть тонны вопросов относительно контекста создания экземпляров.

Пример, приведенный MSalters, проблематичен:

template <typename T> void foo() {
  T() + T();
}

рассмотрите следующий код:

#include <iostream>

using namespace std;


template <typename T> void foo() {
  T() + T();
}

class A {};

void operator +(const A&, const A&)
{
    cout << "Called operator+(const A&, const A&)" <<endl;
}

int main()
{
    foo<A>();
}

Это компилируется и запускается на всех компиляторах, но если вы поместите определение класса A в пространство имен:

#include <iostream>

using namespace std;


template <typename T> void foo() {
    T() + T();
}

namespace {
   class A {};
}


void operator+(const A&, const  A&)
{
    cout << "operator+(const N::A&, const N::A&)" << endl;
}

int main()
{
     foo<A>();
}

Clang не сможет скомпилироваться, но VC ++ и gcc скомпилируются. Зачем? какой компилятор соответствует спецификации?

Честно говоря, я не знаю. Какой-то компилятор, такой как gcc, даже противоречит сам себе в этой области. Рассмотрим следующий код:

#include <iostream>

using namespace std;


template <typename T> void foo() {
    g(T());
}

namespace {
   class A {};
}


void g(A a)
{
    cout << "g(A)" << endl;
}

int main()
{
    foo<A>();
}

Просто измените с "operator +" на функцию с именем "g", gcc не сможет скомпилировать ??? Почему ???

Если спецификация верна, то почему GCC не может найти 'g'?

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

Когда я читал Бьярна Страуструпа "Язык программирования C ++, 4-е издание", 26.3.5 Шаблоны и пространства имен, у него был такой пример:

namespace N{
    class A{};
    char f(A);
}

char f(int);

template<typename T>
char g(T t)
{
    return f(t);       //choose f() depending on what T is
}

char f(double);

char c1 = g(N::A());   //causes N::f(N::A) to be called
char c2 = g(2);        //causes f(int) to be called
char c3 = g(2.1);      //causes f(int) to be called, f(double) not considered

Здесь f (t) явно зависит, поэтому мы не можем связать f в точке определения. Чтобы сформировать специализацию для g (N :: A), компилятор ищет в пространстве имен N функции с именем f () и ребра N :: f (N :: A).

Значение f (int) найдено, поскольку оно находится в области видимости в точке определения шаблона. F (double) не найден, потому что он не находится в области видимости в точке определения шаблона, и зависимый от аргумента поиск не находит, что глобальная функция принимает только аргументы встроенных типов.

Так что это беспорядок!

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