【问题标题】:Specialize a Template Function to Generate a Compile-Time Error特化模板函数以生成编译时错误
【发布时间】:2014-06-16 15:57:21
【问题描述】:

如果用户尝试使用给定的模板参数调用该函数,如何专门化模板函数以在编译时生成错误?

通过使用以下成语,我能够为模板 class 获得这种行为...

template <typename T>
class MyClass< std::vector<T> >;

我要修改的函数的基本签名是...

template <typename T>
T bar(const int arg) const {
  ...
}

如果我使用与禁止某些模板相同的范式...

template<>
std::string foo::bar(const int arg) const;

我可以生成链接器错误,我认为这比运行时错误更可取,但仍然不是我想要的。

由于我无法使用 C++11,我无法使用 static_assert,如 here 所述。相反,我正在尝试像这样使用BOOST_STATIC_ASSERT...

template<>
std::string foo::bar(const int arg) const {
  BOOST_STATIC_ASSERT(false);
  return "";
}

但是,这会产生以下编译时错误,即使我尝试使用我试图禁止的模板参数调用函数的实例...

error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE<false>'

我找到了this post,但它并没有真正提供我认为适用于我的任何见解。有人可以帮忙吗?

【问题讨论】:

  • 嗯,也许你可以用这个link
  • 函数模板的显式特化就像一个简单的函数,所以任何静态断言都会触发。
  • @Sumsar1812,你指的是哪个链接?
  • 这就是你的建议...BOOST_STATIC_ASSERT(typeid(std::string) != typeid(T));这会引发编译器错误...error: 'typeid' operator cannot appear in a constant-expression
  • 什么是foo?一个命名空间,一个类?

标签: c++ templates boost static-assert


【解决方案1】:

使用boost::is_same 生成一个编译时布尔值,然后可以与BOOST_STATIC_ASSERT 一起使用来执行检查。

template <typename T>
T bar(const int) 
{
  BOOST_STATIC_ASSERT_MSG((!boost::is_same<T, std::string>::value), 
                          "T cannot be std::string");
  return T();
}

bar<int>(10);
bar<std::string>(10);  // fails static assertion

Live demo

【讨论】:

  • 这会引发(不需要的)编译时错误...BOOST_STATIC_ASSERT(!boost::is_same&lt;T, std::string&gt;::value, "my message"); 产生 error: macro "BOOST_STATIC_ASSERT" passed 3 arguments, but takes just 1error: 'BOOST_STATIC_ASSERT' was not declared in this scope。请注意,我打电话给BOOST_STATIC_ASSERT(true) 没有问题。
  • @DanForbes 注意到我的示例中额外的一组括号了吗? :) 如果没有这些,is_same 中的逗号会被预处理器解释为参数分隔符。另外,您需要BOOST_STATIC_ASSERT_MSG 是否要添加消息。
  • 德普。接受这个答案,因为它很简单并且提供了我正在寻找的确切行为。
【解决方案2】:

好像C++不允许专门的模板成员函数。所以如果你想使用相同的接口,你应该使用其他技术。我想使用 trait_type 来实现这个。

template <class T>
struct is_string : false_type {};
template <>
struct is_string<string> : true_type {};

template <typename T>
class MyClass {
 private:
  T bar(const int arg, false_type) const {
    return T();
  }

  std::string bar(const int arg, true_type) const {
    return "123";
  }
 public:
  T bar(const int arg) const {
    return bar(arg, is_string<T>());
  }
};

如果你不能使用C++11,你必须自己实现false_type和true_type。或者您可以使用专门的模板类。

【讨论】:

  • 虽然我很欣赏你的回答,而且它可能会奏效,但上面@Praetorian 提供的答案要简单得多,并且提供了我正在寻找的确切行为。
  • 我很确定 std::true_typestd::false_type 在 C++03 中不是吗?或者至少在 TR1 中?
  • @MooingDuck 仅在 TR1 中。
  • C++ 允许(完全)专门化模板成员函数。但问题不在于它。即使将std::string 作为模板参数传递,您的代码也能成功编译。
猜你喜欢
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-30
  • 1970-01-01
  • 2013-03-11
  • 1970-01-01
相关资源
最近更新 更多