From 48217d5acf5ea8f4ca44c184992ef5150cd7e157 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 25 Oct 2020 13:42:41 -0400 Subject: [PATCH] Macros to simplify usage of class template AttachedVirtualFunction ... ... And allow correct linkage when overrides are defined in dynamically loaded modules --- .../lib-registries/AttachedVirtualFunction.h | 52 ++++++++++++------- .../labeltrack/ui/LabelTrackControls.cpp | 7 +-- .../labeltrack/ui/LabelTrackShifter.cpp | 3 +- src/tracks/labeltrack/ui/LabelTrackView.cpp | 3 +- .../notetrack/ui/NoteTrackControls.cpp | 7 +-- .../notetrack/ui/NoteTrackShifter.cpp | 3 +- .../notetrack/ui/NoteTrackView.cpp | 3 +- .../wavetrack/ui/WaveTrackControls.cpp | 7 +-- .../wavetrack/ui/WaveTrackShifter.cpp | 3 +- .../wavetrack/ui/WaveTrackView.cpp | 3 +- src/tracks/timetrack/ui/TimeTrackControls.cpp | 7 +-- src/tracks/timetrack/ui/TimeTrackView.cpp | 3 +- src/tracks/ui/TimeShiftHandle.cpp | 3 +- src/tracks/ui/TimeShiftHandle.h | 1 + src/tracks/ui/TrackControls.cpp | 3 +- src/tracks/ui/TrackControls.h | 1 + src/tracks/ui/TrackView.cpp | 6 +-- src/tracks/ui/TrackView.h | 2 + 18 files changed, 57 insertions(+), 60 deletions(-) diff --git a/libraries/lib-registries/AttachedVirtualFunction.h b/libraries/lib-registries/AttachedVirtualFunction.h index bc6554a98..9374ecb01 100644 --- a/libraries/lib-registries/AttachedVirtualFunction.h +++ b/libraries/lib-registries/AttachedVirtualFunction.h @@ -72,13 +72,15 @@ AttachedVirtualFunction< AbstractHost, // class to be switched on by runtime type int, double // other arguments >; +// Allow correct linkage for overrides defined in dynamically loaded modules: +DECLARE_EXPORTED_ATTACHED_VIRTUAL(AUDACITY_DLL_API, DoSomething); ``` Definitions needed: ``` //file Client.cpp -// Define the default function body here (as a function returning a function!) -template<> auto DoSomething::Implementation() -> Function { +// Define the default function body here +DEFINE_ATTACHED_VIRTUAL(DoSomething) { return [](AbstractHost &host, int arg1, double arg2) { return ErrorCode::Ok; }; @@ -86,9 +88,6 @@ template<> auto DoSomething::Implementation() -> Function { // at runtime if the virtual function is invoked for a host subclass for which no override // was defined. } -// Must also guarantee construction of an instance of class DoSomething at least -// once before any use of DoSomething::Call() -static DoSomething registerMe; ``` Usage of the method somewhere else: @@ -124,7 +123,7 @@ Overrides of the method, defined in any other .cpp file: // An override of the function, building up a hierarchy of function bodies parallel // to the host class hierarchy using DoSomethingSpecial = DoSomething::Override< SpecialHost >; -template<> template<> auto DoSomethingSpecial::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoSomethingSpecial) { // The function can be defined without casting the first argument return [](SpecialHost &host, int arg1, double arg2) { return arg1 == 0 ? ErrorCode::Ok : ErrorCode::Bad; @@ -135,8 +134,7 @@ static DoSomethingSpecial registerMe; // A further override, demonstrating call-through too using DoSomethingExtraSpecial = DoSomething::Override< ExtraSpecialHost, DoSomethingSpecial >; -template<> template<> -auto DoSomethingExtraSpecial::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoSomethingExtraSpecial) { return [](ExtraSpecialHost &host, int arg1, double arg2){ // Call the immediately overridden version of the function auto result = Callthrough( host, arg1, arg2 ); @@ -173,11 +171,7 @@ public: //! At least one static instance must be created; more instances are harmless /*! (There will be others if there are any overrides.) */ - AttachedVirtualFunction() - { - static std::once_flag flag; - std::call_once( flag, []{ Register( Implementation() ); } ); - } + AttachedVirtualFunction(); //! For defining overrides of the method /*! @@ -280,11 +274,33 @@ private: }; using Registry = std::vector< Entry >; - static Registry &GetRegistry() - { - static Registry registry; - return registry; - } + static Registry &GetRegistry(); }; +//! Typically follow the `using` declaration of a new AttachedVirtualFunction with this macro +#define DECLARE_EXPORTED_ATTACHED_VIRTUAL(DECLSPEC, Name) \ + template<> DECLSPEC Name::AttachedVirtualFunction(); \ + template<> auto DECLSPEC Name::GetRegistry() -> Registry &; \ + template<> auto DECLSPEC Name::Implementation() -> Function + +//! Used in the companion .cpp file to the .h using the above macro; followed by a function body +#define DEFINE_ATTACHED_VIRTUAL(Name) \ + template<> Name::AttachedVirtualFunction() \ + { \ + static std::once_flag flag; \ + std::call_once( flag, []{ Register( Implementation() ); } ); \ + } \ + template<> auto Name::GetRegistry() -> Registry & \ + { \ + static Registry registry; \ + return registry; \ + } \ + static Name register ## Name ; \ + template<> auto Name::Implementation() -> Function + +//! Used to define overriding function; followed by a function body +#define DEFINE_ATTACHED_VIRTUAL_OVERRIDE(Name) \ + static Name register ## Name ; \ + template<> template<> auto Name::Implementation() -> Function \ + #endif diff --git a/src/tracks/labeltrack/ui/LabelTrackControls.cpp b/src/tracks/labeltrack/ui/LabelTrackControls.cpp index 43bda6fbd..cf819e0a0 100644 --- a/src/tracks/labeltrack/ui/LabelTrackControls.cpp +++ b/src/tracks/labeltrack/ui/LabelTrackControls.cpp @@ -179,16 +179,14 @@ PopupMenuTable *LabelTrackControls::GetMenuExtension(Track *) } using DoGetLabelTrackControls = DoGetControls::Override< LabelTrack >; -template<> template<> auto DoGetLabelTrackControls::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetLabelTrackControls) { return [](LabelTrack &track) { return std::make_shared( track.SharedPointer() ); }; } -static DoGetLabelTrackControls registerDoGetLabelTrackControls; using GetDefaultLabelTrackHeight = GetDefaultTrackHeight::Override< LabelTrack >; -template<> template<> -auto GetDefaultLabelTrackHeight::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(GetDefaultLabelTrackHeight) { return [](LabelTrack &) { // Label tracks are narrow // Default is to allow two rows so that NEW users get the @@ -196,4 +194,3 @@ auto GetDefaultLabelTrackHeight::Implementation() -> Function { return 73; }; } -static GetDefaultLabelTrackHeight registerGetDefaultLabelTrackHeight; diff --git a/src/tracks/labeltrack/ui/LabelTrackShifter.cpp b/src/tracks/labeltrack/ui/LabelTrackShifter.cpp index 8a075f3ed..51670d8e6 100644 --- a/src/tracks/labeltrack/ui/LabelTrackShifter.cpp +++ b/src/tracks/labeltrack/ui/LabelTrackShifter.cpp @@ -248,9 +248,8 @@ private: }; using MakeLabelTrackShifter = MakeTrackShifter::Override; -template<> template<> auto MakeLabelTrackShifter::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(MakeLabelTrackShifter) { return [](LabelTrack &track, AudacityProject &project) { return std::make_unique(track, project); }; } -static MakeLabelTrackShifter registerMakeLabelTrackShifter; diff --git a/src/tracks/labeltrack/ui/LabelTrackView.cpp b/src/tracks/labeltrack/ui/LabelTrackView.cpp index 43456b5d8..02353b60e 100644 --- a/src/tracks/labeltrack/ui/LabelTrackView.cpp +++ b/src/tracks/labeltrack/ui/LabelTrackView.cpp @@ -2290,12 +2290,11 @@ int LabelTrackView::DialogForLabelName( } using DoGetLabelTrackView = DoGetView::Override< LabelTrack >; -template<> template<> auto DoGetLabelTrackView::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetLabelTrackView) { return [](LabelTrack &track) { return std::make_shared( track.SharedPointer() ); }; } -static DoGetLabelTrackView registerDoGetLabelTrackView; std::shared_ptr LabelTrackView::DoGetVRulerControls() { diff --git a/src/tracks/playabletrack/notetrack/ui/NoteTrackControls.cpp b/src/tracks/playabletrack/notetrack/ui/NoteTrackControls.cpp index 622b6de8f..cf9bb72d4 100644 --- a/src/tracks/playabletrack/notetrack/ui/NoteTrackControls.cpp +++ b/src/tracks/playabletrack/notetrack/ui/NoteTrackControls.cpp @@ -321,22 +321,19 @@ void NoteTrackControls::ReCreateVelocitySlider( wxEvent &evt ) } using DoGetNoteTrackControls = DoGetControls::Override< NoteTrack >; -template<> template<> auto DoGetNoteTrackControls::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetNoteTrackControls) { return [](NoteTrack &track) { return std::make_shared( track.SharedPointer() ); }; } -static DoGetNoteTrackControls registerDoGetNoteTrackControls; #include "../../../ui/TrackView.h" using GetDefaultNoteTrackHeight = GetDefaultTrackHeight::Override< NoteTrack >; -template<> template<> -auto GetDefaultNoteTrackHeight::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(GetDefaultNoteTrackHeight) { return [](NoteTrack &) { return NoteTrackControls::DefaultNoteTrackHeight(); }; } -static GetDefaultNoteTrackHeight registerGetDefaultNoteTrackHeight; #endif diff --git a/src/tracks/playabletrack/notetrack/ui/NoteTrackShifter.cpp b/src/tracks/playabletrack/notetrack/ui/NoteTrackShifter.cpp index 0b15997c3..9f41f16db 100644 --- a/src/tracks/playabletrack/notetrack/ui/NoteTrackShifter.cpp +++ b/src/tracks/playabletrack/notetrack/ui/NoteTrackShifter.cpp @@ -54,9 +54,8 @@ private: }; using MakeNoteTrackShifter = MakeTrackShifter::Override; -template<> template<> auto MakeNoteTrackShifter::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(MakeNoteTrackShifter) { return [](NoteTrack &track, AudacityProject&) { return std::make_unique(track); }; } -static MakeNoteTrackShifter registerMakeNoteTrackShifter; diff --git a/src/tracks/playabletrack/notetrack/ui/NoteTrackView.cpp b/src/tracks/playabletrack/notetrack/ui/NoteTrackView.cpp index 9ca3ac9b8..59a7ca9c1 100644 --- a/src/tracks/playabletrack/notetrack/ui/NoteTrackView.cpp +++ b/src/tracks/playabletrack/notetrack/ui/NoteTrackView.cpp @@ -60,12 +60,11 @@ std::vector NoteTrackView::DetailedHitTest } using DoGetNoteTrackView = DoGetView::Override< NoteTrack >; -template<> template<> auto DoGetNoteTrackView::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetNoteTrackView) { return [](NoteTrack &track) { return std::make_shared( track.SharedPointer() ); }; } -static DoGetNoteTrackView registerDoGetNoteTrackView; std::shared_ptr NoteTrackView::DoGetVRulerControls() { diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackControls.cpp b/src/tracks/playabletrack/wavetrack/ui/WaveTrackControls.cpp index bfc21532b..1e2ce36ec 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackControls.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackControls.cpp @@ -1253,19 +1253,16 @@ void WaveTrackControls::ReCreatePanSlider( wxEvent &event ) } using DoGetWaveTrackControls = DoGetControls::Override< WaveTrack >; -template<> template<> auto DoGetWaveTrackControls::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetWaveTrackControls) { return [](WaveTrack &track) { return std::make_shared( track.SharedPointer() ); }; } -static DoGetWaveTrackControls registerDoGetWaveTrackControls; using GetDefaultWaveTrackHeight = GetDefaultTrackHeight::Override< WaveTrack >; -template<> template<> -auto GetDefaultWaveTrackHeight::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(GetDefaultWaveTrackHeight) { return [](WaveTrack &) { return WaveTrackControls::DefaultWaveTrackHeight(); }; } -static GetDefaultWaveTrackHeight registerGetDefaultWaveTrackHeight; diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackShifter.cpp b/src/tracks/playabletrack/wavetrack/ui/WaveTrackShifter.cpp index c1201e34a..bf70d2ab4 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackShifter.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackShifter.cpp @@ -188,9 +188,8 @@ private: }; using MakeWaveTrackShifter = MakeTrackShifter::Override; -template<> template<> auto MakeWaveTrackShifter::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(MakeWaveTrackShifter) { return [](WaveTrack &track, AudacityProject&) { return std::make_unique(track); }; } -static MakeWaveTrackShifter registerMakeWaveTrackShifter; diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp b/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp index e78518aae..addd3b3c4 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp @@ -1043,12 +1043,11 @@ void WaveTrackView::DoSetMinimized( bool minimized ) } using DoGetWaveTrackView = DoGetView::Override< WaveTrack >; -template<> template<> auto DoGetWaveTrackView::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetWaveTrackView) { return [](WaveTrack &track) { return std::make_shared( track.SharedPointer() ); }; } -static DoGetWaveTrackView registerDoGetWaveTrackView; std::shared_ptr WaveTrackView::DoGetVRulerControls() { diff --git a/src/tracks/timetrack/ui/TimeTrackControls.cpp b/src/tracks/timetrack/ui/TimeTrackControls.cpp index dac2f980f..bc84477ee 100644 --- a/src/tracks/timetrack/ui/TimeTrackControls.cpp +++ b/src/tracks/timetrack/ui/TimeTrackControls.cpp @@ -170,20 +170,17 @@ PopupMenuTable *TimeTrackControls::GetMenuExtension(Track *) } using DoGetTimeTrackControls = DoGetControls::Override< TimeTrack >; -template<> template<> auto DoGetTimeTrackControls::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetTimeTrackControls) { return [](TimeTrack &track) { return std::make_shared( track.SharedPointer() ); }; } -static DoGetTimeTrackControls registerDoGetTimeTrackControls; #include "../../ui/TrackView.h" using GetDefaultTimeTrackHeight = GetDefaultTrackHeight::Override< TimeTrack >; -template<> template<> -auto GetDefaultTimeTrackHeight::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(GetDefaultTimeTrackHeight) { return [](TimeTrack &) { return 100; }; } -static GetDefaultTimeTrackHeight registerGetDefaultTimeTrackHeight; diff --git a/src/tracks/timetrack/ui/TimeTrackView.cpp b/src/tracks/timetrack/ui/TimeTrackView.cpp index 6c2c8cc7f..b545ac6a1 100644 --- a/src/tracks/timetrack/ui/TimeTrackView.cpp +++ b/src/tracks/timetrack/ui/TimeTrackView.cpp @@ -53,12 +53,11 @@ std::vector TimeTrackView::DetailedHitTest } using DoGetTimeTrackView = DoGetView::Override< TimeTrack >; -template<> template<> auto DoGetTimeTrackView::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetTimeTrackView) { return [](TimeTrack &track) { return std::make_shared( track.SharedPointer() ); }; } -static DoGetTimeTrackView registerDoGetTimeTrackView; std::shared_ptr TimeTrackView::DoGetVRulerControls() { diff --git a/src/tracks/ui/TimeShiftHandle.cpp b/src/tracks/ui/TimeShiftHandle.cpp index 2e78a6538..5289cbc2e 100644 --- a/src/tracks/ui/TimeShiftHandle.cpp +++ b/src/tracks/ui/TimeShiftHandle.cpp @@ -272,12 +272,11 @@ bool CoarseTrackShifter::SyncLocks() return false; } -template<> auto MakeTrackShifter::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL(MakeTrackShifter) { return [](Track &track, AudacityProject&) { return std::make_unique(track); }; } -static MakeTrackShifter registerMakeTrackShifter; void ClipMoveState::Init( AudacityProject &project, diff --git a/src/tracks/ui/TimeShiftHandle.h b/src/tracks/ui/TimeShiftHandle.h index e01de3055..15f34e6ca 100644 --- a/src/tracks/ui/TimeShiftHandle.h +++ b/src/tracks/ui/TimeShiftHandle.h @@ -198,6 +198,7 @@ private: struct MakeTrackShifterTag; using MakeTrackShifter = AttachedVirtualFunction< MakeTrackShifterTag, std::unique_ptr, Track, AudacityProject&>; +DECLARE_EXPORTED_ATTACHED_VIRTUAL(AUDACITY_DLL_API, MakeTrackShifter); class ViewInfo; diff --git a/src/tracks/ui/TrackControls.cpp b/src/tracks/ui/TrackControls.cpp index a338ead9b..b7da1d0ac 100644 --- a/src/tracks/ui/TrackControls.cpp +++ b/src/tracks/ui/TrackControls.cpp @@ -37,7 +37,6 @@ const TrackControls &TrackControls::Get( const Track &track ) return Get( const_cast< Track& >( track ) ); } -template<> auto DoGetControls::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL(DoGetControls) { return nullptr; } -static DoGetControls registerDoGetControls; diff --git a/src/tracks/ui/TrackControls.h b/src/tracks/ui/TrackControls.h index 56d648efb..4ff2d201e 100644 --- a/src/tracks/ui/TrackControls.h +++ b/src/tracks/ui/TrackControls.h @@ -38,5 +38,6 @@ AttachedVirtualFunction< std::shared_ptr< TrackControls >, Track >; +DECLARE_EXPORTED_ATTACHED_VIRTUAL(AUDACITY_DLL_API, DoGetControls); #endif diff --git a/src/tracks/ui/TrackView.cpp b/src/tracks/ui/TrackView.cpp index b73d89703..9c397f8d5 100644 --- a/src/tracks/ui/TrackView.cpp +++ b/src/tracks/ui/TrackView.cpp @@ -229,12 +229,10 @@ static const AudacityProject::AttachedObjects::RegisteredFactory key{ } -template<> auto DoGetView::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL(DoGetView) { return nullptr; } -static DoGetView registerDoGetView; -template<> auto GetDefaultTrackHeight::Implementation() -> Function { +DEFINE_ATTACHED_VIRTUAL(GetDefaultTrackHeight) { return nullptr; } -static GetDefaultTrackHeight registerGetDefaultTrackHeight; diff --git a/src/tracks/ui/TrackView.h b/src/tracks/ui/TrackView.h index da8ed5ea3..5890b7ede 100644 --- a/src/tracks/ui/TrackView.h +++ b/src/tracks/ui/TrackView.h @@ -113,6 +113,7 @@ AttachedVirtualFunction< std::shared_ptr< TrackView >, Track >; +DECLARE_EXPORTED_ATTACHED_VIRTUAL(AUDACITY_DLL_API, DoGetView); struct GetDefaultTrackHeightTag; @@ -122,5 +123,6 @@ AttachedVirtualFunction< int, Track >; +DECLARE_EXPORTED_ATTACHED_VIRTUAL(AUDACITY_DLL_API, GetDefaultTrackHeight); #endif