检查表达式是否编译的便携式方法

dev*_*oln 5 c++ templates template-meta-programming c++11

我需要一种可移植的方法来定义模板类,该模板类检查其参数上某些表达式的有效性。理想情况下,它应该在 MSVC 2013+、Clang 3.1+ 和 GCC 4.8+ 中同样工作。

使用示例:

struct MyStruct
{
    int Back() {return 5;}
};
static_assert(HasBack<MyStruct>::value, "Back must exist!");
Run Code Online (Sandbox Code Playgroud)

我尝试了这段代码:

template<typename T, typename dummy=void> struct HasBack: std::false_type {};
template<typename T> struct HasBack<T, void_t<decltype(declval<T>().Back())>>: std::true_type {};
Run Code Online (Sandbox Code Playgroud)

它在 clang 中工作,但在 Visual Studio 中不起作用。特别是为此,我使用编译器扩展编写了另一个实现:

template<typename T> struct HasBack
{
    __if_exists(void_t<decltype(declval<T>().Back())>) {enum {value=1};}
    __if_not_exists(void_t<decltype(declval<T>().Back())>) {enum {value=0};}
};
Run Code Online (Sandbox Code Playgroud)

它可以在 Visual Studio 2013+ 中编译和工作,但它会在包含此代码的任何项目中完全禁用 IntelliSense。是否有解决这些问题的方法,或者可能有一些不同的方法来进行表达式检查,适用于所有编译器?

max*_*x66 4

以下代码使用我的 g++ (4.9.2) 和我的 clang++ (3.5) 进行编译。

抱歉,我没有 MSVC,所以我不确定它是否适合您。

#include <utility>
#include <type_traits>

template <typename T>
struct HasBack
 {
   template<typename U>
      static decltype(std::declval<U>().Back(), std::true_type{}) func (std::remove_reference_t<U>*); 

   template<typename U>    
      static std::false_type func (...);

   using  type = decltype(func<T>(nullptr));

   static constexpr bool value { type::value };
 };

struct MyStruct
 { int Back() {return 5;} };

static_assert(true  == HasBack<MyStruct>::value, "yes");
static_assert(false == HasBack<int>::value,      "no");

int main ()
 { return 0; }
Run Code Online (Sandbox Code Playgroud)

我希望这对我有帮助,并对我的英语不好表示歉意。

- - 编辑 - -

std::declval根据 aschepler 的更正修改后的示例(添加使用)(谢谢!)

---编辑2 ---

按照 PaulMcKenzie 的建议,我在rextester中编译了示例;似乎也适用于 VS 2015。

---编辑3 ---

根据 GLmonster 的观察进行修改(std::remove_reference<U>*而不是U*作为func().

  • 如果“U”不可默认构造,则“U().Back()”不起作用。这就是“std::declval”的目的。 (2认同)