Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inheritance and is_detected_v provides a strange result (C++17)

I have simplified version of code:

#include <experimental/type_traits>

template<class T> using has_data_t = decltype(T::data());

template <class B> constexpr auto get_data() {
    return std::experimental::is_detected_v<has_data_t, B>;
}
    
template <typename Topt> struct opt_base {
    static constexpr bool i = get_data<Topt>();
  //static constexpr auto j = get_data<Topt>(); // fail to compile
};

struct opt : public opt_base<opt> {
    static int data() { return 7;}
};

int main() {
    static_assert(std::experimental::is_detected_v<has_data_t, opt>);
}

This code compiles. But if you will uncomment commented line then assert fails. It was tested with GCC 7.1 and Clang 4.0.0. Compilation parameters: -std=c++1z -O3 -Wall. Demo

like image 892
DuchIvan Avatar asked May 04 '17 22:05

DuchIvan


1 Answers

In this code:

static constexpr bool i = get_data<Topt>();
static constexpr auto j = get_data<Topt>();

Topt (that is, opt) isn't complete yet. So is_detected_v<has_data_t, opt> is should be false. But by the time we get to main, opt is complete. And so we'd expect is_detected_v<has_data_t, opt> to be true.

Having a template that when instantiated in different contexts yields different results means that your program is ill-formed, no diagnostic required. See [temp.point]:

A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.

The addition of j doesn't really matter - it just happened to flip the switch that changed the order of the way the compiler chose to instantiate things. The program is ill-formed regardless of the presence of j.

like image 143
Barry Avatar answered Nov 20 '22 18:11

Barry