GLmonster GLmonster - 4 months ago 16
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?

Answer

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.