Шаблонная функция для шаблонного (Armadillo) класса [duplicate]

Это даст вам некоторое представление о том, как Java действительно работает до такой степени, что в следующем обсуждении о передаче Java по ссылке или передаче по значению вы просто будете улыбаться: -)

Шаг один, пожалуйста, удалите из вашего разума это слово, которое начинается с «p» «_ _ _ _ _ _ _», особенно если вы исходите из других языков программирования. Java и «p» не могут быть записаны в одной книге, форуме или даже в txt.

Шаг два помнит, что при передаче объекта в метод, по которому вы передаете ссылку Object, а не сам объект

  • Студент : Мастер, означает ли это, что Java является передачей по ссылке?
  • Мастер : Grasshopper, No.

Теперь подумайте о том, что ссылка / переменная объекта делает /:

  1. Переменная содержит биты, которые сообщают JVM, как получить к ссылочному объекту в памяти (куча).
  2. При передаче аргументов методу вы НЕ передаете ссылочную переменную, а копию битов в ссылочной переменной. Что-то вроде этого: 3bad086a. 3bad086a представляет способ доступа к переданному объекту.
  3. Итак, вы просто передаете 3bad086a, что это значение ссылки.
  4. Вы передаете значение ссылки и не самой ссылкой (а не объекта).
  5. Это значение фактически КОПИРОВАНО и дано методу .

В следующем (пожалуйста, не пытайтесь скомпилировать / выполнить это ...):

1. Person person;
2. person = new Person("Tom");
3. changeName(person);
4.
5. //I didn't use Person person below as an argument to be nice
6. static void changeName(Person anotherReferenceToTheSamePersonObject) {
7.     anotherReferenceToTheSamePersonObject.setName("Jerry");
8. }

Что происходит?

  • Переменная person создана в строке # 1, а в начале она равна нулю.
  • В объекте # 2, сохраненном в памяти, создан новый объект Person, а переменной person присваивается ссылка на объект Person. То есть, его адрес. Скажем, 3bad086a.
  • Переменная person , удерживающая адрес объекта, передается функции в строке # 3.
  • В строке # 4 вы можете прослушивать звук молчания
  • Проверить комментарий на строке # 5
  • Локальная переменная метода - anotherReferenceToTheSamePersonObject - создана, а затем идет магическая строка # 6: переменная / ссылка person копируется по битам и передается в anotherReferenceToTheSamePersonObject внутри функции. Никаких новых экземпляров Person не создается. Оба « person » и « anotherReferenceToTheSamePersonObject « сохраняют одно и то же значение 3bad086a. Не пытайтесь это, но человек == anotherReferenceToTheSamePersonObject будет правдой. Обе переменные имеют ИДЕНТИФИКАЦИОННЫЕ КОПИИ ссылки, и оба они относятся к одному объекту Person, SAME Object on the Heap и NOT A COPY.

Изображение стоит тысячи слов:

Pass by Value [/g12]

Обратите внимание, что стрелки anotherReferenceToTheSamePersonObject направлены к объекту а не к переменному человеку!

Если вы этого не поняли, просто доверьтесь мне и помните, что лучше сказать, что Java проходит по значению. Ну, пройдем по эталонному значению. Ну, еще лучше pass-by-copy-of-the-variable-value! ;)

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

Вы всегда передайте копию битов значения ссылки!

  • Если это примитивный тип данных, эти биты будут содержать значение самого примитивного типа данных.
  • Если это объект, в котором бит будет содержать значение адреса, сообщающего JVM, как добраться до объекта.

Java - это пропускная способность, потому что внутри метода вы можете измените ссылочный объект столько, сколько хотите, но как бы вы ни старались, вы никогда не сможете изменить переданную переменную, которая будет поддерживать привязку (а не p _ _ _ _ _ _ _) того же объекта независимо от того, что!


Вышеуказанная функция changeName никогда не сможет изменить фактическое содержимое (битовые значения) переданной ссылки. В другом слове changeName не может заставить Person лицо ссылаться на другой Object.


Конечно, вы можете сократить его и просто сказать, что Java является передачей по значению!

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

5 ответов

940
ответ дан Alan 31 August 2018 в 16:31
поделиться

Этот ответ должен быть довольно коротким и сладким, чтобы ответить (часть) озаглавленного вопроса. Если вы хотите получить более подробный ответ, объясняющий, почему вы должны их там поместить, пожалуйста, перейдите здесь .


Общее правило для размещения typename в основном, когда вы используете параметр шаблона, и хотите получить доступ к вложенному typedef или с использованием псевдонима, например:

template<typename T>
struct test {
    using type = T; // no typename required
    using underlying_type = typename T::type // typename required
};

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

template<typename T>
struct test {
    // typename required
    using type = typename std::conditional<true, const T&, T&&>::type;
    // no typename required
    using integer = std::conditional<true, int, float>::type;
};

Общие правила добавления определителя template в основном аналогичны, за исключением они обычно включают шаблонные функции-члены (статические или другие) структуры / класса, которые сами шаблоны, например:

Учитывая эту структуру и функцию:

template<typename T>
struct test {
    template<typename U>
    void get() const {
        std::cout << "get\n";
    }
};

template<typename T>
void func(const test<T>& t) {
    t.get<int>(); // error
}

Попытка доступа t.get<int>() изнутри функции приведет к ошибке:

main.cpp:13:11: error: expected primary-expression before 'int'
     t.get<int>();
           ^
main.cpp:13:11: error: expected ';' before 'int'

Таким образом, в этом контексте вам понадобится ключевое слово template заранее и вызвать его так:

t.template get<int>()

Таким образом, компилятор будет анализировать это правильно, а не t.get < int.

120
ответ дан Community 31 August 2018 в 16:31
поделиться
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 31 August 2018 в 16:31
поделиться

Я помещаю превосходный ответ 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 31 August 2018 в 16:31
поделиться
120
ответ дан Community 31 August 2018 в 16:32
поделиться
Другие вопросы по тегам:

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