Несколько вопросов о моменте создания шаблона - PullRequest
3 голосов
/ 18 октября 2019

Во-первых, процитированный отрывок некоторого стандарта

Если на специализацию шаблона X ссылаются в контексте, который зависит от параметра-шаблона какого-либо окружающего шаблона Y, данная точка инстанции зависит от точкиинстанции Y.
Если X является специализацией шаблона функции, точка инстанцирования является точкой Y.
Если X является специализацией шаблона класса, точка инстанцирования находится непосредственно перед точкой инстанцирования Y.

В противном случае данный момент создания объекта привязывается к расположению декларации / определения области действия пространства имен (D), в котором содержится оператор, ссылающийся на X.
Если X является специализацией шаблона функции, точкаинстанцирование происходит сразу после D.
Если X является специализацией шаблона класса, точка инстанцирования находится непосредственно перед D.

Какой-то код здесь

#include <iostream>
template<int N>
struct state {
    friend auto call(state<N>);
};
template<int N>
struct add_state {
    friend auto call(state<N>) {
        return N;
    }
};
template<typename T, int N>
T show() {
    add_state<N> d;
    return T{};
}
template<typename T,int N>
class data {
public:
    T c = show<T,N>();
};
#1,#3,#2
int main() {
    data<int, 0> t;
    call(state<0>{});
}

Итак, согласнок приведенным выше правилам, когда создается экземпляр класса data<int, 0>, то точкаэкземпляра находится в # 1.

Тогда show<T,N> зависит от параметров шаблона данных класса шаблона. Таким образом, точка создания для show<int,0> находится на # 2.

Тогда add_state<N> зависит от параметров шаблона функции шаблона шоу. Таким образом, в соответствии с правилами точка инстанцирования для add_state<0> находится на # 3.

На # 3 auto call(state<0>) определено, call(state<0>{}) должно быть связано, но на самом деле компилятор сообщает об ошибкахследующим образом:

лязг:

main.cpp:24:2: error: function 'call' with deduced return type cannot be used before it is defined
        call(state<0>{});
        ^
main.cpp:4:14: note: 'call' declared here
        friend auto call(state<N>);
                    ^
1 error generated.

г ++:

main.cpp: In function ‘int main()’:
main.cpp:24:17: error: use of ‘auto call(state<0>)’ before deduction of ‘auto’
  call(state<0>{});
                 ^ 

Почему? В моем понимании о точке инстанции есть ошибки? Если нет, почему компилятор сообщает об этих ошибках?

Ответы [ 4 ]

2 голосов
/ 22 октября 2019

Согласно [temp.inst] /2.1, когда создается неявный экземпляр шаблона класса, создается только объявление друзей:

Неявное создание специализация шаблона класса вызывает неявное создание деклараций , но не определений , аргументов по умолчанию или спецификаторов noexcept для функций-членов класса, классов-членов, перечислений членов-областей, статических данныхучастники, шаблоны участников и друзья ;

Так что на # 3 auto call(state<N>) только объявлено. Более того, эта декларация не найдена при обычном поиске безоговорочного имени.

Тем не менее, я не думаю, что она делает ваш код неправильно сформированным. Ваш код настолько странен, что вполне возможно, что о такой ситуации никогда не думали стандартные члены комитета или разработчики компилятора: обычные встроенные функции-друзья определены в классе, который делает функцию-друга видимой через ADL (Argument Dependent Name Lookup). Это, конечно, также то, что ожидает компилятор.

Так что в call(state<0>{}) внутри main объявление call находится в ADL внутри определения state, а компилятор просто не думаето поиске потенциального определения этой функции в как-то не связанном классе add_state. Таким образом, он не может вывести auto.

0 голосов
/ 21 октября 2019

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

#include <iostream>

// forward declaration of the
// add_state template
template<int>
struct add_state;


template<int N>
struct state {
    // Note: we generate the state here
    // so that the compiler will see the
    // definition of the call function
    add_state<N> t;
    friend auto call(state<N>);
};
template<int N>
struct add_state {
    friend auto call(state<N>) {
        return N;
    }
};


int main() {
    auto val = call(state<42>{});
    std::cout << val << std::endl;

    return 0;
}

Я не уверен, поможет ли это. Но я надеюсь, что и мне тоже будет интересно хорошее объяснение.

0 голосов
/ 21 октября 2019

Ваша проблема здесь:

template<int N>
struct state {
    friend auto call(state<N>);//<--no way of telling return type !
};

Компилятор абсолютно не может сказать, что возвращает функция call и должен отказаться. Исправление также очевидно, просто дайте ему что-нибудь для работы, например:

1006 *
0 голосов
/ 18 октября 2019

Если используется int вместо auto, появляется ошибка:

main.cpp:15: undefined reference to `call(state<0>)'
collect2.exe: error: ld returned 1 exit status

При добавлении {return N;} к friend int call(state<N>) работает нормально. Затем заменили обратно int на auto, тоже работает.

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