38

根据 C++1y/C++14 N3690,变量模板特化的类型是否必须与主模板的类型相同?

template<int x>
char y = f(x);

template<>
double y<42> = g();

如果是这样,是否有可能以某种方式使主要未定义?

template<int x>
???? y = ???; // undefined

template<>
double y<42> = g();

草案中的哪些内容?

类模板的等效功能是:

template<int x>
struct S
{
    static char y;
};

template<>
struct S<42>
{
    static double y;
};

template<int x>
struct S; // undefined

template<>
struct S<42>
{
    static double y;
};
4

5 回答 5

35

变量模板特化的类型是否必须与主模板的类型相同?

不,变量模板的显式(或部分)特化可以指定与隐式实例化所隐含的类型不同的类型。在为 Clang 实现该功能时,我们发现规范中没有要求在这种情况下匹配类型的规则,我们将此问题提交给 C++ 核心工作组,并确认此遗漏是故意的。

是否有可能以某种方式离开主要未定义?

不指定类型就不可能声明主变量模板——没有任何语法允许这样的事情。

草案中的哪些内容?

这两者都被省略了——没有要求类型匹配的规则,也没有声明没有类型的变量模板的语法。所以我不能指出标准的任何特定部分并说“这就是规则不存在的地方”。

如果您有权访问 C++ 标准委员会的反射器,请参阅以 core-23901 开头的线程以进行讨论。

于 2014-01-23T20:52:01.433 回答
3

以下使用 clang trunk 编译-std=c++1y

#include <iostream>

template<int x>
char y = 3;

template<>
double y<42> = 2.5;

char c {y<17>};

double d {y<42>};

因此,变量模板的特化不需要与其主模板具有相同的类型,或者 clang 有一个错误的 N3690 实现

于 2013-10-01T05:52:05.603 回答
1

我完全期望专业化的声明需要与主模板完全匹配,包括它的类型。这对于变量模板来说并不是什么新鲜事。我还没有追查标准中的细节,看看它在哪里指定了这个细节。

下面的代码似乎做了一些类似于你想要的事情,即,让变量类型保持开放:

#include <iostream>

template <int X> struct var_type { typedef int type; };
template <> struct var_type<42> { typedef double type; };

int    f(int x) { return x; }
double g()    { return 3.14; }

template <int X>
typename var_type<X>::type var = f(X);
template <>
typename var_type<42>::type var<42> = g();

int main()
{
    std::cout << "var<17>=" << var<17> << '\n';
    std::cout << "var<42>=" << var<42> << '\n';
}
于 2013-10-01T05:26:25.890 回答
0

推断 Clang 正在表达旨在标准化的功能有点冒险。(注意:这个答案我没有提到任何东西。)

当然,允许更改类型的后果是您无法在以任何方式引用模板后对其进行专门化,而对于所有其他类型的模板,截止时间是 ODR 使用的。除非他们正在计划一些古怪的事情,否则这看起来像是一个 Clang 错误。

您始终可以使用类型模板来声明变量模板的类型。

template< typename t >
struct x_type { typedef … type; };

template< typename t >
typename x_type< t >::type x = …;

现在x_type可能是专业的。这只是防止 Clang 当前存在错误的可能性。它不允许您引用不确定类型的对象。C++ 只是不支持这一点。引用对象 ODR-使用类模板特化。

于 2013-10-01T06:26:47.450 回答
0

如果是这样,是否有可能以某种方式使主要未定义?

我认为这有效地做到了:

template<class T> std::enable_if_t<sizeof(T*)==0> var;
template<> auto var<float >  = 1;
template<> auto var<double>  = 2;

var<char>,例如,似乎是一个无效的变量。

对于非类型模板参数(NTTA)的情况,我想这更棘手,因为您需要考虑所有不可实例化的情况

template<int x> std::enable_if_t<x!=42 and x!=43> var;
template<> auto var<42>  = 1;
template<> auto var<43>  = 2;

在这种情况下,var<41>是uninstanstiable。

我不确定这有多强大。它适用于 clang 和 gcc:https ://godbolt.org/z/hxcnjMrce

最后,可能更具可读性:

template<class T> auto var  = std::enable_if_t<sizeof(T*)==0>{};
template<int x>   auto var2 = std::enable_if_t<x!=42 and x!=43>{};

编辑:实际上 NTTA 更容易,唯一的挑战是使布尔表达式依赖于参数x

template<int x> auto var2 = std::enable_if_t<x!=x>{};
template<> auto var2<42>  = 1;
template<> auto var2<43>  = 2;

这是受另一个技巧的启发:https ://devblogs.microsoft.com/oldnewthing/20200311-00/?p=103553

于 2021-05-07T02:31:03.560 回答