CAF: at least one type has no ID - Compiles on Linux but not Windows

192 views Asked by At

I have a proof of concept example that uses the C++ actor framework and Cmake, the issue is that it works fine on Linux but runs into what looks to be a CAF issue on Windows. The provided CAF examples compile fine on both platforms but I cannot understand why my proof of concept example (Duck Party) errors out. Unfortunately you need quite a bit of code to repoduce, here is the repo:

https://github.com/dylan-baros/duck_party

The error that I see on Windows is:

Severity Code Description Project File Line Suppression State Error C2338 static_assert failed: 'at least one type has no ID, did you forgot to announce it via CAF_ADD_TYPE_ID?' DuckParty C:\Users\dbaros\Documents\Repos\duck_party\build_deps\caf-src\libcaf_core\caf\mixin\sender.hpp 73

To Reproduce

Using Visual Studio 2022 Community Edition (Visual Studio 17 2022)

  1. Clone the repo
  2. Navigate to the root directory
  3. mkdir build
  4. cd build
  5. cmake ..
  6. cmake --build . (Or navigate to the solution using Visual Studio and build)

I have also included a provided CAF example (helloworld) in the Example folder that builds fine using cmake.

What I have Tried

I thought perhaps it was CMake at first but I think I have ruled that out since the helloworld example builds fine using the compiled caf libaries and cmake. I tried adding CAF_ADD_TYPE_ID for the types that are defined in CustomMessages.h as atoms but I get an error that they have already been defined.

1

There are 1 answers

0
neverlord On

In the line that triggers this compiler error, you are trying to send a std::chrono::system_clock::time_point. This is what CAF is complaining about, because this type has no type ID assigned. Neither by CAF per default nor in your application via CAF_ADD_TYPE_ID.

I cannot tell you why this is working on Linux for you, maybe GCC's or Clang's definition of the system clock type accidentally matches caf::timestamp on Linux.

In any case, caf::timestamp is the portable way to send timestamps around in CAF and this type is announced by default (i.e., has a type ID).

I got your example compiling using these changes:

diff --git a/source/DuckParty/CMakeLists.txt b/source/DuckParty/CMakeLists.txt
index fdf749b..6cdb857 100644
--- a/source/DuckParty/CMakeLists.txt
+++ b/source/DuckParty/CMakeLists.txt
@@ -16,7 +16,7 @@ target_include_directories(DuckParty
 )
 
 target_link_libraries(DuckParty
-    PRIVATE CAF::internal CAF::core duck_classes pthread
+    PRIVATE CAF::internal CAF::core duck_classes
 )
 
 
diff --git a/source/DuckParty/DisplayActor.h b/source/DuckParty/DisplayActor.h
index 73a8b77..ae8ad4e 100644
--- a/source/DuckParty/DisplayActor.h
+++ b/source/DuckParty/DisplayActor.h
@@ -9,7 +9,7 @@
 #include "Displayable.h"
 
 using DisplayActor = caf::typed_actor<
-   caf::result<void>(display_behavior, std::chrono::time_point<std::chrono::system_clock>, std::string)>;
+   caf::result<void>(display_behavior, caf::timestamp, std::string)>;
 
 class DisplayState {
    public:
@@ -20,8 +20,10 @@ class DisplayState {
 
        DisplayActor::behavior_type make_behavior() {
            return {
-               [this](display_behavior, std::chrono::time_point<std::chrono::system_clock> quack_time, std::string behavior) {
-                   displayable_->DisplayBehavior(quack_time, behavior);
+               [this](display_behavior, caf::timestamp quack_time, std::string behavior) {
+               using sys_dur_t = std::chrono::system_clock::duration;
+                   auto sys_time = std::chrono::time_point_cast<sys_dur_t>(quack_time);
+                   displayable_->DisplayBehavior(sys_time, behavior);
                }
            };
        }
diff --git a/source/DuckParty/DuckActor.h b/source/DuckParty/DuckActor.h
index eb92d3c..9ddf651 100644
--- a/source/DuckParty/DuckActor.h
+++ b/source/DuckParty/DuckActor.h
@@ -1,6 +1,7 @@
 #pragma once
 #include <chrono>
 #include <caf/typed_event_based_actor.hpp>
+#include <caf/type_id.hpp>
 #include "CustomMessages.h"
 
 #include "Duck.h"
@@ -27,7 +28,7 @@ class DuckState {
            return {
            [this](do_duck_behavior) {
                self_->delayed_send(self_, std::chrono::milliseconds(milliseconds_), do_duck_behavior_v);
-               std::chrono::time_point<std::chrono::system_clock> quackTime = std::chrono::system_clock::now();
+               auto quackTime = caf::make_timestamp();
                std::string duck_display = duck_->GetFlyBehavior() + " " + duck_->GetNoiseBehavior();
                self_->send(display_actor_, display_behavior_v, quackTime, duck_display);
                }
diff --git a/source/DuckParty/main.cpp b/source/DuckParty/main.cpp
index 1a10d73..3f199c0 100644
--- a/source/DuckParty/main.cpp
+++ b/source/DuckParty/main.cpp
@@ -24,7 +24,7 @@ void caf_main(caf::actor_system& sys) {
    DuckActor duck_actor3 = sys.spawn<DuckImpl>(move(duck3), 1500, display_actor);
 
    caf::scoped_actor self(sys);
-   self->send(display_actor, display_behavior_v, std::chrono::system_clock::now(), "Let's get this party started!");
+   self->send(display_actor, display_behavior_v, caf::make_timestamp(), "Let's get this party started!");
 }
 
 CAF_MAIN(caf::id_block::duck_msg_types)

I didn't run any binaries, but at least it compiled for me on Windows 10 with recent Visual Studio (Community Edition).

The static_assert in CAF unfortunately does not produce which of the types fails the check. However, you can use static_assert(caf::has_type_id_v<T>) to check your types one-by-one before calling send to quickly find the offending type.

Hope that helps you to move forward with your project.