Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在内联constexpr函数中使用变量模板而不公开变量模板?_C++_C++14_Variable Templates - Fatal编程技术网

C++ 在内联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

是否可以在内联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 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);
}