簡體   English   中英

C++17 模板參數推導失敗

[英]C++17 Template argument deduction failed

我想模擬計時器,它會定期調用一個函數(回調),因為我寫了以下代碼片段(雖然很幼稚),其中,參數推導在主函數中的 Timer/ <int, int, float> /.. 行失敗。 我正在用 c++17 std 編譯這段代碼。 我該如何解決這個問題? 或者那些必要的論點? 在這方面的任何幫助表示贊賞。

#include <functional>
#include <chrono>

using namespace std::chrono_literals;

template<typename ...Args>
class Timer
{
public:
  Timer(std::function<void(Args...)> func, Args&&... args, std::chrono::milliseconds step)
    : m_callback{ func },
      m_args{ std::forward<Args>(args)... },
      m_time{ step },
      m_stop{ false },
  { }

private:
  std::function<void(Args...)> m_callback;
  std::thread m_executer;
  std::tuple<Args...> m_args;
  std::chrono::milliseconds m_time;
  bool m_stop;
};

int main()
{
  // Create a timer
  auto timer = Timer/*<int, int, float>*/([](int a, int b, float c) { }, 15, 17, 12.0f, 500ms);

  return 0;
}

我刪除了與您的問題無關的所有內容(您應該這樣做以使其更容易獲得幫助),這就是我要做的工作。 首先,我在可變參數之前移動了毫秒。 它可能會混淆參數包結束的編譯器,因此您通常希望 ... 成為參數列表中的最后一件事。

其次,由於需要將 lambda 轉換為 std::function 才能匹配,因此 CTAD(類模板 arg 推導)對您不起作用。

如果 main() 按預期將實際的 std::function 傳遞給構造函數,則它可以工作:

auto timer = Timer(
    std::function<void(int, int, float)>([](int a, int b, float c) { }),
    500ms, 15, 17, 12.0f);

但這可以說比你最初嘗試的更糟糕。

更好的解決方法(有點模糊)是幫助 CTAD 弄清楚您在使用 c++17演繹指南做什么。 這是一個模式匹配說,“如果他們嘗試使用這種語法創建這個類,它真的意味着它是這種類型。”

這是我找到的適合您的指南:

template <typename T, typename... Args> 
Timer(T&&, std::chrono::milliseconds, Args...) -> Timer<Args...>;

本指南的作用是說:他們可以將任何 T&& 作為第一個參數傳遞,它只是被忽略,然后是 chrono 毫秒,然后是 Args 包中的更多類型。 鑒於此, Timer 的實際類型(箭頭右側)只是 Timer<Args...> 無論它們是什么。 然后繼續,您的函數只需要可轉換為 std::function 即可。

現在它與您的 lambda 匹配,使用給定的 Args 實例化 Timer,並由此知道它可以將您的 lambda 轉換為 std::function。

這是一個工作示例,減去所有不相關的內容:

#include <functional>
#include <chrono>

using namespace std::chrono_literals;

template<typename ...Args>
struct Timer {
  Timer(std::function<void(Args...)> func,  std::chrono::milliseconds step, Args&&... args )
  { }
};

template <typename T, typename... Args>
Timer(T&&, std::chrono::milliseconds, Args...) -> Timer<Args...>;

int main() {
    auto timer = Timer([](int a, int b, float c) { }, 500ms, 15, 17, 12.0f);
}

編譯器資源管理器: https : //godbolt.org/z/Wa3oK3

這里模板參數推導有兩個問題。 無法從 lambda 參數中推導出std::function參數,推導僅適用於尾隨參數包。

要解決此問題,您可以更改構造函數的參數順序,如下所示:

Timer(std::function<void(Args...)> func, std::chrono::milliseconds step, Args&&... args)
 // ...                                                              //  ^^^^^^^^^ trailing 

並添加扣除指南

template<typename Func, typename ...Args>
Timer(Func, std::chrono::milliseconds, Args&&...) -> Timer<Args...>;

這是一個演示

請注意警告,您的成員初始值設定項列表與成員聲明的順序不同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM