Is it possible to use a variable template inside an inline constexpr function without also exposing the variable template itself?
For example, this compiles and works:
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>;
}
But this doesn't compile:
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>;
}
The reason seems to be that template declarations aren't allowed in block scope (GCC gives an informative error message about this, Clang doesn't).
To repeat the motivation in a bit more detail, the function is inline and defined in a header, and I'm not interested in exposing the variable template wherever the header is included.
I guess I can define a detail namespace and put the variable template there, but it would be nicer not to expose the variable template at all. Maybe it's not possible.
From the standard we have that:
A template-declaration is a declaration. [...]. A declaration introduced by a template declaration of a variable is a variable template. [...]
And:
A template-declaration can appear only as a namespace scope or class scope declaration.
Therefore no, it isn't allowed.
You can still wrap it in a class and make both the data member and the member function static if you don't want to expose it:
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);
}
Another possible solution is:
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);
}
It has the plus that centsToOctaves
is no longer a member function of C
, as mentioned in the comments.
That being said, I don't understand what prevents you from simply doing this:
template<typename T>
inline constexpr T centsToOctaves(const T cents) {
return cents / T{1200};
}