Das crtp-Beispiel funktioniert auch mit unterschiedlichen Rückgabetypen und constexpr. Hätte sein können daß static_cast in interface() dazwischengrätscht, aber das ist nicht der Fall.
Mit concepts gehts ja sowieso, da kann man bei Bedarf/sinnvoll einschränken (auskommentiert).
namespace pre_alpha
{
template <typename Message>
constexpr decltype(auto) decode(const Message& msg, const uint8_t key) noexcept
{
using type = std::array<char, Message{}.size()>;
type
res;
for (size_t i=0; i<res.size(); ++i)
{
const char x = char(key + i);
res[i] = char(msg[i] ^ x);
}
return res;
}
template <auto Message, uint8_t Key> struct message : std::integral_constant<decltype(decode(Message, Key)), decode(Message, Key)>{};
namespace crtp
{
template <typename Derived>
struct Base
{
constexpr decltype(auto) interface() const noexcept { return static_cast<const Derived*>(this)->implementation(); }
constexpr decltype(auto) implementation() const noexcept { return message<std::to_array<int>({71,109,109,115,117,60,107,113,109,0,69,71,77,4,108,97,111,40}), 23>::value.cbegin(); }
};
struct Derived1 : Base<Derived1>
{
constexpr int implementation() const noexcept { return 42; }
};
struct Derived2 : Base<Derived2>
{
constexpr double implementation() const noexcept { return 3.1415926; }
};
struct Derived3 : Base<Derived3>{};
template <typename Type>
constexpr decltype(auto) getMessage(const Type& base) noexcept { return base.interface(); }
} // crtp
namespace ente
{
struct MessageSeverity
{
constexpr decltype(auto) getMessage() const noexcept { return message<std::to_array<int>({122,94,88,68,64,15,29,17,86,90,81,21,115,89,76,78,83,88,87,81,75,81,39,97,52,44,41,101,21,36,32,60,38,35,35,43,61,44,56,61,145,247,51,48,36,119,34,44,55,123,23,47,55,58,7,18,20,6,22,7,20,2,11,1,15,25,64,77,3,6,4,81,22,22,25,85,35,26,15,28,29,91,191,193,28,26,242,161,230,230,234,165,205,235,237,249,254,228,231,255,239,251,245,255,146}), 42>::value.cbegin(); }
};
struct MessageInformation
{
constexpr int getMessage() const noexcept { return 42; }
};
struct MessageWarning
{
constexpr double getMessage() const noexcept { return 3.1415926; }
};
struct MessageFatal : MessageSeverity{};
template <typename Type>
concept MessageServer = requires(Type t)
{
t.getMessage();
//std::is_same_v<int, decltype(t.getMessage())>;
};
template <MessageServer Type>
constexpr decltype(auto) getMessage(const Type& messServer) noexcept { return messServer.getMessage(); }
} // ente
} // pre_alpha
int main()
{
using namespace pre_alpha;
crtp::Derived1 d1;
constexpr auto d1r = crtp::getMessage(d1);
std::cout << d1r << std::endl;
crtp::Derived2 d2;
constexpr auto d2r = crtp::getMessage(d2);
std::cout << d2r << std::endl;
crtp::Derived3 d3;
constexpr auto d3r = crtp::getMessage(d3);
std::cout << d3r << std::endl;
std::cout << std::endl;
ente::MessageInformation mi;
constexpr auto mir = ente::getMessage(mi);
std::cout << mir << std::endl;
ente::MessageWarning mw;
constexpr auto mwr = ente::getMessage(mw);
std::cout << mwr << std::endl;
ente::MessageFatal mf;
constexpr auto mfr = ente::getMessage(mf);
std::cout << mfr << std::endl;
return EXIT_SUCCESS;
}