Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.net  
   

Die mobilen Seiten von c++.net:
https://m.c-plusplus.net

  
C++ Forum :: WinAPI ::  Der Fluch der variadischen Templates mit Exceptions...oder der Blödheit?     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
FrankTheFox
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.02.2007
Beiträge: 245
Beitrag FrankTheFox Mitglied 18:02:03 05.10.2017   Titel:   Der Fluch der variadischen Templates mit Exceptions...oder der Blödheit?            Zitieren

Tach :D


Ich hab mal folgendes gemacht:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <windows.h>
#include <stdexcept>
#include <iostream>
#include <string>
#include <sstream>
 
template<typename... Ts> auto ArgumentExpander(Ts&&... ts) -> std::string
{
    std::ostringstream oss;
 
    int temp[] = {0,(static_cast<void>(oss << ts), 0)...};
 
    static_cast<void>(temp);
 
    return(oss.str());
}
 
class C: public std::runtime_error
{
public:
    template<typename... T> C(T&&... t);
 
public:
    virtual ~C() = default;
};
 
template<typename... Ts>C::C(Ts&&... ts):
    std::runtime_error(ArgumentExpander(std::forward<Ts>(ts)...)) {}
 
 
int WINAPI WinMain(
                HINSTANCE /**/,
                HINSTANCE /**/,
                LPSTR /**/,
                int /**/)
{
    C c(1, "aaaaaaaaa", 3 ,"nnnn");
 
    return(0);
}


Das läßt sich kompilieren und ausführen. Da C von std::runtime_error abgeleitet ist so allerdings sinnfrei.


C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int WINAPI WinMain(
                HINSTANCE /**/,
                HINSTANCE /**/,
                LPSTR /**/,
                int /**/)
{
    try{
        throw C(1, "aaaaaaaaa", 3 ,"nnnn");
    }
    catch(const C& ex)
    {
        std::cout << ex.what();
    }
 
    return(0);
}


Hier führt das Kompilieren allerdings schon zum Fehler...

Code:
In instantiation of 'std::__cxx11::string ArgumentExpander(Ts&& ...) [with Ts = {C}; std::__cxx11::string = std::__cxx11::basic_string<char>]':
 
required from 'C::C(Ts&& ...) [with T = {C}]'


Das Problem ist der folgende Aufruf throw C(1, "aaaaaaaaa", 3 ,"nnnn");


Kommentiere ich explicit aus, dann läßt es sich kompilieren und ausführen.


Ich benutze hier ein variadic Template (enthält mindestens einen Parameter Pack). In der Funktion ArgumentExpander wird der Pack ausgepackt.
Ich dachte bis jetzt das folgendes gemacht wird:

Code:
'std::__cxx11::string ArgumentExpander(Ts&& ...) [with Ts = {int, const char (&)[10], int, const char (&)[5]}


TS wird also nach und nach ausgepackt...in exakt genau fünf Parameter.
In der Funktion ArgumentExpander wird das temp array idiom dazu "missbraucht" die stream operator für jedes einzelne t im Pack aufzurufen.
Das Problem ist das der ostringstream operator nicht auf die Klasse C (ist wahrscheinlich das this) angewandt werden kann.
Wieso muss explicit im Konstruktor stehen...und wieso vermeidet das den Fehler...with T = {C}]'

edit:

Das Problem taucht auf beim mingw

Code:
x86_64-w64-mingw32-g++.exe -Wnon-virtual-dtor -Wshadow -Winit-self -Wredundant-decls -Wcast-align -Wundef -Wfloat-equal -Winline -Wunreachable-code -Wmissing-declarations -Wmissing-include-dirs -Wswitch-enum -Wswitch-default -Weffc++ -Wzero-as-null-pointer-constant -pedantic-errors -pedantic -Wfatal-errors -Wextra -Wall -std=c++14 -DUNICODE -D_UNICODE


Dem Visual Studio 2013 ist das wurscht (mit Warning Level: W4)

Gruß

_________________
Im void dahoam!


Zuletzt bearbeitet von FrankTheFox am 19:11:01 05.10.2017, insgesamt 1-mal bearbeitet
Jodocus
Mitglied

Benutzerprofil
Anmeldungsdatum: 06.12.2010
Beiträge: 1404
Beitrag Jodocus Mitglied 21:01:41 05.10.2017   Titel:              Zitieren

Füg mal noch
C++:
C(C&& c) : std::runtime_error{ std::move(c) } { }
ein und gut ist.

_________________
Quak
FrankTheFox
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.02.2007
Beiträge: 245
Beitrag FrankTheFox Mitglied 21:15:11 05.10.2017   Titel:              Zitieren

Jo, iss gut :live:

Magst du mich kurz erleuchten, warum der Move-Konstruktor das Explicit beim "Template-Konstruktor" überflüssig macht und dann auch der Fehler (required from...) nicht mehr auftritt. Das Visual Studio hat sich komischerweise darüber nie aufgeregt.

Danke :)

_________________
Im void dahoam!
hustbaer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.10.2006
Beiträge: 23809
Beitrag hustbaer Mitglied 01:48:51 06.10.2017   Titel:              Zitieren

Also erstmal... damit du was werfen kannst muss es einen copy- oder move-ctor haben.

FrankTheFox schrieb:
Kommentiere ich explicit aus, dann läßt es sich kompilieren und ausführen.

Nein, umgekehrt. Wenn du den template-ctor explicit machst läßt es sich kompilieren. Denn dann passt er nicht mehr als Vorlage für einen copy- oder move-ctor, da diese nicht explicit sein können. Und da er nicht mehr passt, und es auch sonst keinen passenden userdefinierten ctor gibt, bekommst du einen compilergenerierten. Und der funktioniert.

Wenn der template-ctor dagegen nicht explicit ist, dann gilt er als Vorlage, und der Compiler versucht daraus einen move-ctor zu erstellen. Was nicht geht, da dein Template versucht alle ctor-Argumente über ArgumentExpander in einen Stream zu stopfen. Was mit C nicht geht, weil es den passenden operator nicht gibt.

VS 2013 ist es vermutlich einfach deswegen wurst, weil VS 2013 da nen Bug hat. VS 2017 verweigert deinen Code ohne explicit genau so zu compilieren wie Clang oder GCC.


Die Lösung von Jodocus ist übrigens auch nur ne halbe Sache. Das funktioniert zwar in deinem Beispiel, aber in anderen Situationen, z.B. wenn ein copy-ctor für ein benanntes Objekt gesucht wird, wird wieder der selbe Fehler kommen. Siehe dazu z.B.:
https://mpark.github.io/p ....... -forwarding-constructors/

_________________
Until every person can enjoy all their human rights, we will not stop. I support Amnesty International. Will you?
https://www.amnesty.org / https://www.amnesty.de / https://www.amnesty.at
FrankTheFox
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.02.2007
Beiträge: 245
Beitrag FrankTheFox Mitglied 14:26:40 07.10.2017   Titel:              Zitieren

Die Testklasse heißt mal B und fn ist der ArgumentExpander.


C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class B: public std::runtime_error
{
public:
 
    B(): std::runtime_error("Unknown error"){}
    virtual ~B() = default;
 
    template<class ... Args,std::enable_if_t<(sizeof...(Args)>1), bool> = true>
    B(Args &&...args): std::runtime_error(fn(std::forward<Args>(args)...))
    {
        std::cout<<"ctor1: ";
    }
 
    template<class Arg,std::enable_if_t<!std::is_base_of<B, std::remove_reference_t<Arg>>::value, bool> = true>
    B(Arg && arg): std::runtime_error(fn(std::forward<Arg>(arg)))
    {
        std::cout<<"ctor2: ";
    }
 
    B(const B &b): std::runtime_error(b.what())
    {
        std::cout<<"ctor3: ";
    }
 
    B(B && b): std::runtime_error(std::move(b))
    {
        std::cout<<"ctor4: ";
    }
};




hustbaer schrieb:
Also erstmal... damit du was werfen kannst muss es einen copy- oder move-ctor haben.


Den habe ich jetzt ;)

hustbaer schrieb:

Nein, umgekehrt. Wenn du den template-ctor explicit machst läßt es sich kompilieren....


ja..das hatte ich gemeint...nur nicht geschrieben.

hustbaer schrieb:

VS 2013 ist es vermutlich einfach deswegen wurst, weil VS 2013 da nen Bug hat. VS 2017 verweigert deinen Code ohne explicit genau so zu compilieren wie Clang oder GCC.


dann sollte jetzt auch VS2017 nicht meckern.

Die Tests...
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
try{
        int a{1};
        std::string s{"ddddddd"};
 
        //throw B(s, a);
        //throw B(s);
        //throw B("aaa", 1,2, "ccc");
        throw B("aaaaaaaaaaaaaaaaaaaaaaa");
    }
    //catch(const B& b)
    catch(B b)
    {
        std::cout << b.what();
    }


scheinen aber zu funktionieren, nur was für ein Aufriss :eek:

vielleicht sollte ich mal...

C++:
try{
   //...
   throw std::runtime_error(fn("aaaa","bbbb",23));
}
catch(const std::runtime_error& ex){
   std::cout << ex.what() << std::endl;
}


ins Auge fassen. Ist halt nur keine so schöne eigene Exceptionklasse.

Gruß

_________________
Im void dahoam!


Zuletzt bearbeitet von FrankTheFox am 14:39:35 07.10.2017, insgesamt 1-mal bearbeitet
hustbaer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.10.2006
Beiträge: 23809
Beitrag hustbaer Mitglied 19:03:54 07.10.2017   Titel:              Zitieren

Ich würde den Ctor einfach explicit machen. Ich mach' sowieso grundsätzlich alle ctor explicit die ich nicht wirklich implicit brauche. Was spricht da dagegen?

_________________
Until every person can enjoy all their human rights, we will not stop. I support Amnesty International. Will you?
https://www.amnesty.org / https://www.amnesty.de / https://www.amnesty.at


Zuletzt bearbeitet von hustbaer am 19:06:04 07.10.2017, insgesamt 1-mal bearbeitet
C++ Forum :: WinAPI ::  Der Fluch der variadischen Templates mit Exceptions...oder der Blödheit?   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.net ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info und www.c-plusplus.net enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.