为什么一些看起来像普通类型定义的表达式意外地变成了模板声明?

Why some expression that looks like a definition for normal types unexpectedly turns out to be a declaration for templates?

这些表达式都是普通类型的定义:

int num;
bool flag;

但是一些看起来像普通类型定义的表达式意外地变成了模板的声明(详情见下文和https://ibb.co/k0qCHp2)!

这里是相关的代码片段(https://godbolt.org/z/a9W9Wc):

    #include<iostream>
    template<typename T>
    class Test
    {
    public:
        static constexpr int sdm = T(nullptr);
        static int f(void){static_assert(sizeof(T)==0);}
        int g(void){static_assert(sizeof(T)==0);}
    };
    
    int main()
    {
       Test<int> intTest;  //**O'DWYER says that it's a declaration instead of a definition in his talk(see https://ibb.co/k0qCHp2)! Why?** 
       //But I can get this object's address indeed.
       std::cout << &intTest << std::endl;
    }

如果Test<int> intTest;是声明,我可以得出结论std::vector<int> vec;std::map<std::string, int> map也是声明。我说得对吗?

Test<int> intTest;是变量intTest的定义(也是声明,所有定义也是声明)。但是,这个事实与您隐含的“为什么这条线编译”的问题无关。它编译的原因是:它导致 class 模板特化 Test<int> 的隐式实例化,但 不是 其成员函数和静态数据成员。

[temp.inst]/2 The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or noexcept-specifiers of the class member functions, member classes, scoped member enumerations, static data members, member templates, and friends...

[temp.inst]/9 An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class, a static data member of a class template, or a substatement of a constexpr if statement (9.4.1), unless such instantiation is required...

那些成员函数和静态数据成员在使用时会被隐式实例化;正是在这一点上,编译器会发现他们的定义是错误的,并发出适当的诊断。

[temp.inst]/3 Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.