C ++-шаблон вложенных typename [duplicate]

В java все ссылается, поэтому, когда у вас есть что-то вроде: Point pnt1 = new Point(0,0); Java делает следующее:

  1. Создает новый объект Point
  2. Создает новую ссылку на точку и инициализирует эта ссылка на точку (см.) на ранее созданном объекте Point.
  3. Отсюда, через жизнь объекта Point, вы получите доступ к этому объекту через ссылку pnt1. Поэтому мы можем сказать, что в Java вы манипулируете объектом по его ссылке.

enter image description here [/g7]

Java не передает аргументы метода по ссылке; он передает их по значению. Я буду использовать пример из этого сайта :

public static void tricky(Point arg1, Point arg2) {
  arg1.x = 100;
  arg1.y = 100;
  Point temp = arg1;
  arg1 = arg2;
  arg2 = temp;
}
public static void main(String [] args) {
  Point pnt1 = new Point(0,0);
  Point pnt2 = new Point(0,0);
  System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); 
  System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);
  System.out.println(" ");
  tricky(pnt1,pnt2);
  System.out.println("X1: " + pnt1.x + " Y1:" + pnt1.y); 
  System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);  
}

Поток программы:

Point pnt1 = new Point(0,0);
Point pnt2 = new Point(0,0);

Создание двух разных объектов Point с двумя различными ссылками , enter image description here [/g8]

System.out.println("X1: " + pnt1.x + " Y1: " +pnt1.y); 
System.out.println("X2: " + pnt2.x + " Y2: " +pnt2.y);
System.out.println(" ");

Как и ожидалось, выход будет:

X1: 0     Y1: 0
X2: 0     Y2: 0

В этой строке «pass-by-value» переходит в игру ...

tricky(pnt1,pnt2);           public void tricky(Point arg1, Point arg2);

Ссылки pnt1 и pnt2 передаются по значению сложному методу, что означает, что теперь ваши ссылки pnt1 и pnt2 имеют свои copies с именем arg1 и arg2. Так же pnt1 и arg1 указывают на тот же объект. (То же самое для pnt2 и arg2) enter image description here [/g9]

В методе tricky:

 arg1.x = 100;
 arg1.y = 100;

enter image description here [/g10]

Далее в методе tricky

Point temp = arg1;
arg1 = arg2;
arg2 = temp;

Здесь вы сначала создаете новую ссылку temp Point, которая будет point в том же месте, что и arg1 справка. Затем вы перемещаете ссылку arg1 в точку в то же место, что и arg2. Наконец, arg2 будет point в том же месте, что и temp.

enter image description here [/g11]

Отсюда область действия tricky метод ушел, и вы больше не имеете доступа к ссылкам: arg1, arg2, temp. Но важно отметить, что все, что вы делаете с этими ссылками, когда они «в жизни», будет постоянно влиять на объект, на который они указывают .

Итак, после выполнения метода tricky, когда вы вернетесь к main, у вас есть такая ситуация: enter image description here [/g12]

Итак, теперь полное выполнение программы будет be:

X1: 0         Y1: 0
X2: 0         Y2: 0
X1: 100       Y1: 100
X2: 0         Y2: 0

913
задан MSalters 1 June 2016 в 12:28
поделиться

4 ответа

940
ответ дан Alan 1 September 2018 в 06:47
поделиться
77
ответ дан Community 1 September 2018 в 06:47
поделиться
typedef typename Tail::inUnion<U> dummy;

Однако я не уверен, что реализация inUnion верна. Если я правильно понимаю, этот класс не должен быть создан, поэтому вкладка «fail» никогда не будет автоматически терпеть неудачу. Возможно, было бы лучше указать, находится ли тип в объединении или нет с простым булевым значением.

template <typename T, typename TypeList> struct Contains;

template <typename T, typename Head, typename Tail>
struct Contains<T, UnionNode<Head, Tail> >
{
    enum { result = Contains<T, Tail>::result };
};

template <typename T, typename Tail>
struct Contains<T, UnionNode<T, Tail> >
{
    enum { result = true };
};

template <typename T>
struct Contains<T, void>
{
    enum { result = false };
};

PS: Посмотрите на Boost :: Variant

PS2: посмотрите на typelists , особенно в книге Андрея Александреску: Modern C ++ Design

18
ответ дан Luc Touraille 1 September 2018 в 06:47
поделиться

Я помещаю превосходный ответ JLBorges на аналогичный вопрос дословно из cplusplus.com, так как это наиболее краткое объяснение, которое я прочитал по этому вопросу.

] В шаблоне, который мы пишем, есть два типа имен, которые можно использовать - зависимые имена и не зависимые имена. Зависимое имя - это имя, которое зависит от параметра шаблона; неизменяемое имя имеет то же значение, независимо от параметров шаблона.

Например:

template< typename T > void foo( T& x, std::string str, int count )
{
    // these names are looked up during the second phase
    // when foo is instantiated and the type T is known
    x.size(); // dependant name (non-type)
    T::instance_count ; // dependant name (non-type)
    typename T::iterator i ; // dependant name (type)

    // during the first phase, 
    // T::instance_count is treated as a non-type (this is the default)
    // the typename keyword specifies that T::iterator is to be treated as a type.

    // these names are looked up during the first phase
    std::string::size_type s ; // non-dependant name (type)
    std::string::npos ; // non-dependant name (non-type)
    str.empty() ; // non-dependant name (non-type)
    count ; // non-dependant name (non-type)
}

То, что зависит от зависимого имени, может быть чем-то другим для каждого конкретного экземпляра шаблона. Как следствие, шаблоны C ++ подвержены «двухфазному поиску имен». Когда шаблон сначала анализируется (до того, как выполняется какое-либо создание), компилятор просматривает не зависящие имена. Когда происходит конкретное создание шаблона, параметры шаблона известны к тому времени, и компилятор ищет зависимые имена.

На первом этапе анализатор должен знать, является ли зависимое имя именем типа или имени не-типа. По умолчанию зависимым именем считается имя не-типа.

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


у вас есть квалифицированное имя, которое относится к типу и зависит от параметра шаблона.

1
ответ дан Nik-Lz 1 September 2018 в 06:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: