Consider the following code snippet:
#include <iostream>
#include <concepts>
template<typename T>
concept Traits = requires(typename T::DispatcherT a, typename T::MsgT& b)
{
{ a.handleMsg(b) } -> std::same_as<void>;
};
struct MsgOne {
int first{1};
};
struct MsgTwo {
int first{10};
double second{100.5};
};
struct DispatcherOne {
void handleMsg(MsgOne& msg) { std::cout << "One: " << msg.first << '\n'; }
};
struct DispatcherTwo {
void handle(MsgTwo msg) { std::cout << "Two: " << msg.first << " " << msg.second << '\n'; }
};
struct TraitsOne {
using DispatcherT = DispatcherOne;
using MsgT = MsgOne;
};
struct TraitsTwo {
using DispatcherT = DispatcherTwo;
using MsgT = MsgTwo;
};
template <Traits T>
struct Driver {
using DispatcherT = typename T::DispatcherT;
using MsgT = typename T::MsgT;
void handleMsg(MsgT &msg) {
dispatcher.handleMsg(msg);
//dispatcher. <- code completion fails to offer handleMsg(..)
}
DispatcherT dispatcher;
};
int main() {
Driver<TraitsOne> driver{};
MsgOne msg{};
driver.handleMsg(msg);
}
the problem that i have here is that Clion IDE (v2022.2) (with clangd(v13) as LSP) does not offer code completion on an instance of DispatcherT inside of Driver<Traits T> template. Restricting the template parameter with a simpler concept such as
template<typename T>
concept Traits = requires(T a, MsgOne& b)
{
{ a.handleMsg(b) } -> std::same_as<void>;
};
works beautifully
but with the more complex Traits, code completion is lost. My question is: what would be an alternative way of defining a container of types that is code-completion friendly? I have thought about std::tuple<> but haven't tried it since accessing the types might be a bit cumbersome (imho). It seems Visual Studio is offering intellisense but I am constrained to use clangd. Any ideas and critisisms are welcome!