C++ 在内联constexpr函数中使用变量模板而不公开变量模板?
是否可以在内联constexpr函数中使用变量模板,而不公开变量模板本身 例如,它编译并工作:C++ 在内联constexpr函数中使用变量模板而不公开变量模板?,c++,c++14,variable-templates,C++,C++14,Variable Templates,是否可以在内联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
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 constexpr T十二个=T(1200.0);
模板
内联constexpr T centsToctaves(const T cents){
退回美分/壹仟贰佰元;
}
但这并没有编译:
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>;
}
模板
内联constexpr T centsToctaves(const T cents){
模板constexpr U十二_一百=U(1200.0);
退回美分/壹仟贰佰元;
}
原因似乎是块范围中不允许使用模板声明(GCC给出了一条关于这一点的信息性错误消息,而Clang没有)
为了更详细地重复这个动机,函数是内联的,并在头中定义,我不想在包含头的任何地方公开变量模板
我想我可以定义一个详细的名称空间并将变量模板放在那里,但最好不要公开变量模板。也许这是不可能的。根据我们的标准: 模板声明是一种声明。[…]。由变量的模板声明引入的声明是变量模板。[……] 以及: 模板声明只能作为命名空间范围或类范围声明出现 因此,不允许这样做。
如果不想公开数据成员和成员函数,仍然可以将其包装在类中,并使其成为静态的:
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);
}
除了使用名称空间之外,还可以将模板变量放入类中,并将其声明为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;
}
当您需要显式地专门化模板变量时,可以改为专门化函数模板
template <>
inline constexpr int centsToOctaves(const int cents) {
using U = int;
return cents / U(1200.0);
}
模板
内联constexpr int centsToctaves(const int cents){
使用U=int;
返回美分/单位(1200.0);
}
但不幸的是,这个解决方案会产生一些重复的代码,可能是更糟糕的。是的,我在上面写过。问题是,是否有办法不公开变量模板。正如我在另一个答案上所写的,不应该假设将自由函数改为类静态函数是可以的,这具有相当广泛的含义。@Nirfiedman您的评论是关于内联函数的,在我看来这是OP的期望。无论如何,交个朋友可以是一个解决办法。让我更新答案。对不起,你是对的,因为我开始写评论,然后他们改为转发,我改了评论。也就是说,本质仍然是这样的:自由函数与静态函数有着完全不同的行为,这是无法调和的。我认为这是最好的答案,可以满足最初的要求。类静态函数的内联是隐含的和冗余的。还有,我不知道你为什么要转发而不是仅仅声明一个朋友?这确实是一个解决方案,但不幸的是,如果将函数嵌入到类中会很麻烦(就像我的情况一样)。@Nirfiedman我首先声明成员函数,然后我意识到,
centsToOctaves
是一个非成员函数,因此,在那一刻,我认为使用成员函数访问私有成员变量更好。然后没有任何进一步的思考。。。你知道发生了什么。你认为你能做的最好的事情就是让它成为一个类的私有(静态)成员,它是你的免费函数的朋友。也就是说,我不认为重复和样板是值得的,只是把它放在一个详细的命名空间里。这是一个非常陈旧的约定,C++不是真正的语言,你可以让坏行为无论如何是不可能的。
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;
}
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);
}