在内联constexpr函数内使用可变模板而不暴露变量模板?
问题描述:
是否可以在内联constexpr函数内使用变量模板而不暴露变量模板本身?在内联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给出了关于这方面的信息错误消息,铛不)。
要更详细地重复动机,该函数是内联的并且在头文件中定义,并且我不想在包含头文件的任何位置公开变量模板。
我想我可以定义一个详细的命名空间,并把变量模板放在那里,但更好的是不暴露变量模板。也许这是不可能的。
答
从标准,我们有:
模板声明是一个声明。 [...]。由变量的模板声明引入的声明是可变模板。 [...]
和:
模板声明只能出现一个命名空间范围或类范围的声明。
因此不,不允许。
你仍然可以把它包装在一个类中,使两者的数据成员和成员函数的静态,如果你不希望暴露它:
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};
}
答
除了使用了命名空间,你也可以把模板变量为一个类,并将其声明为private 。 不允许在函数作用域中声明模板。
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);
}
但不幸的是,这种解决方案会产生一些重复的代码,可能会更糟。
认为你可以做的最好的事情就是让它成为一个私人(静态)成员,一个朋友你的免费功能。也就是说,我不认为重复和样板文件只是把它放在一个详细的命名空间中是值得的。这是一个非常老套的习惯,而C++并不是真正的那种语言,你无论如何都不可能做出不好的行为。 –