0

我一直在尝试新的(ish)C++14 变量模板功能,并在编译期间遇到了这个奇怪的错误(g++ 6.3.0,但也使用 8.1.0 进行了测试)

templated_variables.cpp:32:19: error: wrong number of template arguments (1, should be at least 1)
const std::string config_data<WantName> = "Name: grep";

还有比这更多的错误,但它们都是同一类。代码如下

#include <type_traits>
#include <string>
#include <iostream>

struct Want {};

struct WantName : Want {};
struct WantDir : Want {};

template<bool... values>
struct all_of : std::true_type {};

template<bool... values>
struct all_of<true, values...> : all_of<values...> {};

template<bool... values>
struct all_of<false, values...> : std::false_type {};

template <
  typename Tag, typename ... Tags,
  typename =
    typename std::enable_if<
      all_of<
        std::is_base_of<Want, Tag>::value,
        std::is_base_of<Want, Tags>::value...
      >::value
    >::type
>
const std::string config_data = config_data<Tag> + '\n' + config_data<Tags...>;

template <>
const std::string config_data<WantName> = "Name: grep";

template <>
const std::string config_data<WantDir> = "Directory: /usr/bin/";

int main() {
  std::cout << config_data<WantDir, WantName> << '\n';
  std::cout << config_data<WantDir> << '\n';
  std::cout << config_data<WantName> << '\n';
}

似乎这里的问题是 SFINAE-style std::enable_if,因为如果我删除它,这编译没有问题。config_data<Want*>但奇怪的是,如果我删除with的每个实例config_data<Want*, Want>(或其他一些Want作为基础的类,我们也不会收到编译错误。

我的问题是,我怎样才能避免不得不

(a) 失去阻止此模板的用户传入随机类型作为模板参数的能力,或

(b) 要求在变量模板的每个实例化中使用不必要的基本参数。

我意识到在这个(人为的)例子中,(a)不是一个合理的问题。任何具有不实现其中一种特化的类型的模板实例化都将无法编译。但在一般情况下它肯定会是一个问题,它仍然没有解释为什么用一个有效的第一个参数、一个空的参数包和一个空白的默认参数来实例化模板会导致编译错误。

4

1 回答 1

1

让我们暂时放下实际的默认模板参数,并为最后一个参数命名。

您的主变量模板如下所示:

template <typename Tag, typename... Tags, typename _Unnamed>
const std::string config_data = ...;

你的第一个专业是:

template <>
const std::string config_data<WantName> = ...;

所以在这个专业中,Tag=WantName, Tags={}, and _Unnamedis... 到底是什么?它没有指定。事实上,没有办法实际指定它。有一个尾随的默认模板参数很好,它总是会被默认。但是一旦你尝试专门化它,就不可能做到。

在 C++20 中,您将能够正确地限制这一点:

template <DerivedFrom<Want> Tag, DerivedFrom<Want>... Tags>
const std::string config_data = ...;

在那之前,你真的需要 SFINAE 吗?不完全确定你能从中得到什么。如果你只是放下它,一切都很好。

于 2018-08-02T23:59:42.293 回答