Любопытно повторяющийся шаблон шаблона: ошибка компиляции в gcc7, но ok в gcc6 [duplicate]

$('img').on('load', function() {
    $(this).show()
})

Без библиотек:

window.onload = function() {
   var imgs = document.querySelectorAll('img')
   imgs.onload = function() {
      this.style.display = 'inline';
   }
}
930
задан MSalters 1 June 2016 в 12:28
поделиться

5 ответов

936
ответ дан Alan 19 August 2018 в 03:04
поделиться

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


Общее правило для размещения 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 19 August 2018 в 03:04
поделиться
  • 1
    Хороший материал. Скоро придется перечитывать. +1 – sehe 10 July 2013 в 21:08
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 19 August 2018 в 03:04
поделиться
  • 1
    inUnion & л; U & GT; был бы создан, если вы, например, попытались вызвать Union & lt; float, bool & gt; :: operator = (U) с U == int. Он вызывает частный набор (U, inUnion & lt; U & gt; * = 0). – MSalters 5 March 2009 в 11:52
  • 2
    И работа с result = true / false заключается в том, что мне понадобится boost :: enable_if & lt; & gt ;, что несовместимо с нашей текущей технологической привязкой OSX. Однако отдельный шаблон все же является хорошей идеей. – MSalters 5 March 2009 в 11:55
  • 3
    Люк означает typedef Tail :: inUnion & lt; U & gt; фиктивная; линия. который будет создавать экземпляр Tail. но не inUnion & lt; U & gt ;. он получает экземпляр, когда ему требуется полное его определение. это происходит, например, если вы берете sizeof или получаете доступ к члену (используя :: foo). @MSalters в любом случае, у вас есть еще одна проблема: – Johannes Schaub - litb 5 March 2009 в 15:56
  • 4
    -sizeof (U) никогда не является отрицательным :), потому что size_t представляет собой целочисленный тип без знака. вы получите очень большое количество. вы, вероятно, захотите сделать sizeof (U) & gt; = 1? -1: 1 или подобное :) – Johannes Schaub - litb 5 March 2009 в 15:58
  • 5
    я просто оставил бы его неопределенным и только объявил бы его: template & lt; typename U & gt; struct inUnion; поэтому он, конечно, не может быть создан. я думаю, что имея его с sizeof, компилятор также может дать вам ошибку, даже если вы not создаете экземпляр, потому что если знает sizeof (U) всегда & gt; = 1 и ... – Johannes Schaub - litb 5 March 2009 в 16:07

Я помещаю превосходный ответ 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 только в объявлениях шаблонов и определениях, приведенных ниже.


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

0
ответ дан Nik-Lz 19 August 2018 в 03:04
поделиться
125
ответ дан Community 30 October 2018 в 14:47
поделиться
Другие вопросы по тегам:

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