GLmonster GLmonster - 2 months ago 6x
C++ Question

Portable way to check if expression compiles

I need a portable way to define a template class which checks validity of some expression on its parameter. Ideally it should work identically in MSVC 2013+, Clang 3.1+ and GCC 4.8+.

Usage example:

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

I tried this code:

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 {};

It works in clang, but doesn't work in Visual Studio. Especially for it I wrote another implementation using compiler extensions:

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};}

It compiles and works in Visual Studio 2013+ but it fully disables IntelliSense in any project that includes this code. Is there workarounds for these problems or maybe there is some different way to do expression check, that works for all compilers?


The following code compile with my g++ (4.9.2) and my clang++ (3.5).

Sorry but I don't have a MSVC so I'm not sure it's good for you.

#include <utility>
#include <type_traits>

template <typename T>
struct HasBack
   template<typename U>
      static decltype(std::declval<U>().Back(), std::true_type{}) func (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; }

I hope this helps and sorry for my bad English.

--- EDIT ---

Modified example (adding use of std::declval) according the correction from aschepler (thanks!)

--- EDIT 2 ---

Following the PaulMcKenzie's suggestions, I've compiled the example in rextester; seems to work with VS 2015 too.