The following code does everything I need from it in every C++11 and later compiler I have tried. So, in practice, for my purposes, it works (and is expected to work, at least on Linux, in the foreseeable future, due to historical reasons). However, from a language lawyer perspective, this code is invalid, as it contains a construct (dereference of a pointer to a nonexistent object) that is formally an UD, even though this dereference is actually never executed.
#include <type_traits>
#include <iostream>
namespace n1 {
struct int_based { int base = 0; };
inline int get_base(int_based ib) { return ib.base; }
}
namespace n2 {
struct double_based;
double get_base(const double_based&);
}
template <typename T>
using base_type = decltype((get_base(*(T*)nullptr)));
int main() {
auto isInt = std::is_same<base_type<n1::int_based>, int>::value;
auto isDouble = std::is_same<base_type<n2::double_based>, double>::value;
auto unlike = std::is_same<base_type<n1::int_based>, double>::value;
std::cout << isInt << isDouble << unlike << std::endl;
return 0;
}
The code does Koenig lookup for type mapping and infers the mapped type using function signatures that I would not want to change. In this example, the double_based
type is incomplete; in my real use cases, the types are expected to be complete but are not guaranteed to be DefaultConstructible
. The actual code is a part of a type-safe serialization logic.
The question is: is there a standard-compliant way of "materializing" an object of the template parameter type T
for use in decltype
in this code, or is it impossible to have such standard-complying type mapping without having a preconstructed object of the source type?
Replacing function parameters with pointers to the objects is ugly and doesn't really solve the problem, as it is unclear what these functions need to do with the nullptr
argument in the general case without introducing yet another UB.
Aucun commentaire:
Enregistrer un commentaire