Statische (contexpr) Funktionsabschnitt und Abhängigkeitsinjektion mit Vorlagen in C ++ 23C++

Programme in C++. Entwicklerforum
Anonymous
 Statische (contexpr) Funktionsabschnitt und Abhängigkeitsinjektion mit Vorlagen in C ++ 23

Post by Anonymous »

Ich schreibe einige Unit -Tests für ein C ++ - Projekt. Vor allem versuche ich, einen Test für eine Funktion zu schreiben, die von Recv abhängt. Mit anderen Worten, die Funktion, die ich einen Test für Aufrufe für Aufrufe schreiben möchte, . Es gibt mindestens zwei einfache Ansätze. Eine dieser Implementierungen ist die "reale" Implementierung. Es wickelt Recv . Das andere ist eine "falsche" oder verspottete Implementierung. Virtuelle Funktionsaufrufe und dynamischer Versand zur Laufzeit liefern die Lösung hier. In diesem Fall kann eine einfache Anweisung zur Laufzeit zwischen Real- und Mock -Funktionsaufrufen verwendet werden. Es kann möglich sein, ContExpr oder eine andere Kompilierungszeitlösung zu verwenden, um zwischen dem Aufruf von zwei Implementierungen einer Funktion zu wechseln.
Dies muss möglicherweise mit Abhängigkeitsinjektion kombiniert werden. In diesem Fall kann die Abhängigkeit ein Typ T mit einem Vorlagenparameter eingerichtet sein.

Code: Select all

ssize_t do_logic(
const int sock_fd,
const std::unique_ptr &p_buffer,
const size_t buffer_size
) {

// imagine there is some code block here
{
// code block A
}

ssize_t recv_size = recv(sock_fd, p_buffer.get(), buffer_size, 0);

// imaging there is some code block here
{
// code block B
}

return recv_size;
}

int main() {

int sock_fd = socket(AF_INET, SOCK_STREAM, 0);

// this is all just MWE noise
sockaddr_in server_address;
std::memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(1234);
bind(sock_fd, reinterpret_cast(&server_address), sizeof(server_address));
listen(sock_fd, 10);

const size_t buffer_size = 1024;
const auto p_buffer = std::make_unique(buffer_size);

do_logic(sock_fd, p_buffer, buffer_size);

return 0;
}
Hinweise zu Beachten:

[*] Die Funktion do_logic hat eine Abhängigkeit von Recv . (Eine Funktion aus Sockets Library.) < /Li>

Code: Select all

do_logic
hat auch einen zusätzlichen Code, den ich nicht wiederholt habe. (Trocken) Diese werden durch die Codeblöcke dargestellt, blockieren a und block B .
Hier ist eine Beispiel-Hauptfunktion für einen Unit-Test.

Code: Select all

int main() {

std::string sock_data = "Hello World. This is some example data for unit testing."

const size_t buffer_size = 1024;
const auto p_buffer = std::make_unique(buffer_size);

do_logic(sock_data, p_buffer, buffer_size);

return 0;
}
< /code>
Bisher ist alles in Ordnung. Wir können eine Implementierung von do_logic 
schreiben, bei dem die Funktion Überladung verwendet wird. (Kompilieren Sie die Zeit.) Hier gehen jedoch die Dinge schief.

Code: Select all

ssize_t do_logic(
std::string sock_data,
const std::unique_ptr &p_buffer,
const size_t buffer_size
) {

// imagine there is some code block here
{
// code block A
}

ssize_t recv_size = recv(sock_data, p_buffer.get(), buffer_size);

// imaging there is some code block here
{
// code block B
}

return recv_size;
}
< /code>
Das [url=viewtopic.php?t=15738]Problem[/url] hier ist ein Verstoß gegen Trocken. Während dies funktioniert, ist es nicht ideal, eine Synchronisation von zwei Codeblöcken über zwei verschiedene Dateien in einer Codebasis beizubehalten. Diese Dateien befinden sich wahrscheinlich an sehr unterschiedlichen Stellen im Quellbaum, da eine dieser Dateien für Unit -Tests bestimmt ist, während die andere für den Produktionscode bestimmt ist.  (Nicht hier gezeigt, aber es würde wahrscheinlich STD :: Copy 
oder so aufrufen.)
Gibt es eine Lösung für dieses Problem, die nicht erforderlich ist, um auf Laufzeit -Dispatch zurückzugreifen? Dies ist eine Art Abhängigkeitsinjektion, bei der der Typ in die Funktion injiziert wird.

Code: Select all

template
ssize_t do_logic(
T sock,
const std::unique_ptr &p_buffer,
const size_t buffer_size
) {

// imagine there is some code block here
{
// code block A
}

constexpr if ( /* ? */ ) {
// this `recv`: the `recv` from the sockets library
ssize_t recv_size = recv(sock, p_buffer.get(), buffer_size, 0);
}
else {
// this `recv`: an implementation of a function `recv(std::string, ...etc...)`
// which we write. It could be a null implementation, or it could call
// `std::copy`.
//
// ssize_t recv(std::string, const auto& p_buffer, const auto buffer_size) { return 0; }
//
ssize_t recv_size = recv(sock, p_buffer.get(), buffer_size);
}

// imaging there is some code block here
{
// code block B
}

return recv_size;
}
Für die Zeile ConstExpr if (/ *? */) , was ich tun möchte, ist so etwas wie
constexpr if ( T isa typename int ) { }
else if ( T isa typename std::string ) { }
else {
static_assert("T must be either type int or type std::string");
}
< /code>
Ich habe jedoch keine Ahnung, wie ich das implementieren soll. Ich bin mir vage bewusst, dass C ++ 20 (?) Konzepte eingeführt hat. Aus meiner ersten Lektüre in Konzepte war meine Interpretation jedoch, dass Konzepte eine abstraktere Idee sind, die die Typen zusammengibt. Ich bin mir nicht sicher, ob es das richtige Werkzeug für den Job ist? < /P>
Um ehrlich zu sein, kann es einen einfacheren Ansatz geben als die Idee, die ich hier vorgeschlagen habe. Es ist sehr wahrscheinlich, dass ich dies in die falsche Richtung nehme. Feedback dazu wäre sehr geschätzt. Vielen Dank im Voraus.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post