在不公开变量模板的情况下在内联 constexpr 函数中使用变量模板?
Using a variable template inside inline constexpr function without exposing the variable template?
是否可以在内联 constexpr 函数中使用变量模板而不暴露变量模板本身?
例如,编译并运行:
template<typename T> constexpr T twelve_hundred = T(1200.0);
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
return cents / twelve_hundred<T>;
}
但这不能编译:
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
template<typename U> constexpr U twelve_hundred = U(1200.0);
return cents / twelve_hundred<T>;
}
原因似乎是块范围内不允许模板声明(GCC 给出了关于此的信息性错误消息,Clang 没有)。
为了更详细地重复动机,该函数是内联的并在 header 中定义,我对在包含 header 的任何地方公开变量模板不感兴趣。
我想我可以定义一个详细命名空间并将变量模板放在那里,但最好不要公开变量模板。也许这不可能。
根据我们的标准:
A template-declaration is a declaration. [...]. A declaration introduced by a template declaration of a variable is a variable template. [...]
并且:
A template-declaration can appear only as a namespace scope or class scope declaration.
因此不,这是不允许的。
如果您不想公开它,您仍然可以将其包装在 class 中并将数据成员和成员函数设为静态:
class C {
template<typename T>
static constexpr T twelve_hundred = T(1200.0);
public:
template<typename T>
static constexpr T centsToOctaves(const T cents) {
return cents / twelve_hundred<T>;
}
};
int main() {
C::centsToOctaves(42);
}
另一个可能的解决方案是:
class C {
template<typename T>
static constexpr T twelve_hundred = T(1200.0);
template<typename T>
friend inline constexpr T centsToOctaves(const T cents);
};
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
return cents / C::twelve_hundred<T>;
}
int main() {
centsToOctaves(42);
}
它有加,centsToOctaves
不再是C
的成员函数,如评论中所述
话虽这么说,但我不明白是什么阻止您简单地这样做:
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
return cents / T{1200};
}
除了使用命名空间,您还可以将模板变量放入class,并将其声明为私有。
不允许在函数范围内声明模板。
class Detail {
public:
template<typename T>
static constexpr T centsToOctaves(const T cents) {
return cents / twelve_hundred<T>;
}
private:
template<typename U>
static constexpr U twelve_hundred = U(1200.0);
};
// forwarding
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
return Detail::centsToOctaves<T>(cents);
}
int main() {
centsToOctaves<int>(12);
return 0;
}
不相关:
您可能不需要声明模板 constexpr
变量。由于初始化后无法修改它,因此可以直接使用文字作为替代实现:
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
using U = T;
return cents / U(1200.0);
}
当您需要显式特化模板变量时,您可以特化函数模板。
template <>
inline constexpr int centsToOctaves(const int cents) {
using U = int;
return cents / U(1200.0);
}
但遗憾的是,此解决方案会生成一些重复代码,可能会更糟。
是否可以在内联 constexpr 函数中使用变量模板而不暴露变量模板本身?
例如,编译并运行:
template<typename T> constexpr T twelve_hundred = T(1200.0);
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
return cents / twelve_hundred<T>;
}
但这不能编译:
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
template<typename U> constexpr U twelve_hundred = U(1200.0);
return cents / twelve_hundred<T>;
}
原因似乎是块范围内不允许模板声明(GCC 给出了关于此的信息性错误消息,Clang 没有)。
为了更详细地重复动机,该函数是内联的并在 header 中定义,我对在包含 header 的任何地方公开变量模板不感兴趣。
我想我可以定义一个详细命名空间并将变量模板放在那里,但最好不要公开变量模板。也许这不可能。
根据我们的标准:
A template-declaration is a declaration. [...]. A declaration introduced by a template declaration of a variable is a variable template. [...]
并且:
A template-declaration can appear only as a namespace scope or class scope declaration.
因此不,这是不允许的。
如果您不想公开它,您仍然可以将其包装在 class 中并将数据成员和成员函数设为静态:
class C {
template<typename T>
static constexpr T twelve_hundred = T(1200.0);
public:
template<typename T>
static constexpr T centsToOctaves(const T cents) {
return cents / twelve_hundred<T>;
}
};
int main() {
C::centsToOctaves(42);
}
另一个可能的解决方案是:
class C {
template<typename T>
static constexpr T twelve_hundred = T(1200.0);
template<typename T>
friend inline constexpr T centsToOctaves(const T cents);
};
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
return cents / C::twelve_hundred<T>;
}
int main() {
centsToOctaves(42);
}
它有加,centsToOctaves
不再是C
的成员函数,如评论中所述
话虽这么说,但我不明白是什么阻止您简单地这样做:
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
return cents / T{1200};
}
除了使用命名空间,您还可以将模板变量放入class,并将其声明为私有。 不允许在函数范围内声明模板。
class Detail {
public:
template<typename T>
static constexpr T centsToOctaves(const T cents) {
return cents / twelve_hundred<T>;
}
private:
template<typename U>
static constexpr U twelve_hundred = U(1200.0);
};
// forwarding
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
return Detail::centsToOctaves<T>(cents);
}
int main() {
centsToOctaves<int>(12);
return 0;
}
不相关:
您可能不需要声明模板 constexpr
变量。由于初始化后无法修改它,因此可以直接使用文字作为替代实现:
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
using U = T;
return cents / U(1200.0);
}
当您需要显式特化模板变量时,您可以特化函数模板。
template <>
inline constexpr int centsToOctaves(const int cents) {
using U = int;
return cents / U(1200.0);
}
但遗憾的是,此解决方案会生成一些重复代码,可能会更糟。