我想實作以下行為:
enum class Fruit {
Apple,
Orange,
Pear,
};
template<typename... Args>
void processFruit(Fruit fruit_type, Args&&... args) {
switch (fruit_type) {
case Apple:
processApple(std::forward<Args>args...);
break;
case Orage:
processOrange(std::forward<Args>(args)...);
break;
default:
break;
}
postProcessing();
return;
}
processApple并processOrange采用不同數量的引數。這當然不能編譯。編譯器無法根據該switch陳述句實體化函式。我發現了一些建議static_if。只是想知道我的情況是否有更簡單的方法。謝謝。
ps 我的平臺限制我使用 C 14 解決方案。
uj5u.com熱心網友回復:
你的問題有點混亂,因為你混合了運行時和編譯時邏輯,因為在你的情況下,函式引數的數量和型別取決于某些東西的運行時值。
您現在遇到了兩種不同的選擇:可以使這項作業(即使僅在 C 14 中),但任何未傳遞正確引數的呼叫站點直到運行時才會被檢測到。這樣做的方法是在 和 的幫助std::enable_if_t下。我已經為您的示例完成了此操作,并且在 C 14 模式下為我編譯了以下代碼:decltype()std::declval
#include <iostream>
#include <type_traits>
#include <stdexcept>
enum class Fruit {
Apple,
Orange,
Pear,
};
void processApple(int a, int b);
void processOrange(int c);
void processPear(double d);
void postProcessing();
struct Processor
{
template<typename... Ts, typename = decltype(processApple(std::forward<Ts>(std::declval<Ts>())...))>
static void process(std::integral_constant<Fruit, Fruit::Apple>, Ts&&... ts)
{
processApple(std::forward<Ts>(ts)...);
}
template<typename... Ts, typename = decltype(processOrange(std::forward<Ts>(std::declval<Ts>())...))>
static void process(std::integral_constant<Fruit, Fruit::Orange>, Ts&&... ts)
{
processOrange(std::forward<Ts>(ts)...);
}
template<typename... Ts, typename = decltype(processPear(std::forward<Ts>(std::declval<Ts>())...))>
static void process(std::integral_constant<Fruit, Fruit::Pear>, Ts&&... ts)
{
processPear(std::forward<Ts>(ts)...);
}
[[noreturn]] static void process(...)
{
// While this is inserted, it should never be called in practice,
// unless there's a programming error.
throw std::invalid_argument("Invalid argument specified to processFruit().");
}
};
template<typename... Args>
void processFruit(Fruit fruit_type, Args&&... args) {
switch (fruit_type) {
case Fruit::Apple:
Processor::process(std::integral_constant<Fruit, Fruit::Apple>(), std::forward<Args>(args)...);
break;
case Fruit::Orange:
Processor::process(std::integral_constant<Fruit, Fruit::Orange>(), std::forward<Args>(args)...);
break;
case Fruit::Pear:
Processor::process(std::integral_constant<Fruit, Fruit::Pear>(), std::forward<Args>(args)...);
break;
default:
break;
}
postProcessing();
return;
}
void processApple(int a, int b)
{
std::cout << "Apple: " << a << " // " << b << std::endl;
}
void processOrange(int c)
{
std::cout << "Orange: " << c << std::endl;
}
void processPear(double d)
{
std::cout << "Pear: " << d << std::endl;
}
void postProcessing()
{
std::cout << "Post processing" << std::endl;
}
int main()
{
processFruit(Fruit::Apple, 4, 8);
processFruit(Fruit::Orange, 15);
processFruit(Fruit::Pear, 1.234);
// The following will only throw an exception, but not fail to compile
//processFruit(Fruit::Pear, 1.234, 77);
return 0;
}
(這struct Processor只是為了清理命名空間,它們可能是全域函式。)這里的問題是編譯器無法檢測到錯誤的呼叫,看到注釋掉的呼叫processFruit(Fruit::Pear, 1.234, 77);會產生例外,但編譯器無法檢測到它在編譯時。
在我看來,這不是很明智。由于引數無論如何都取決于Fruit型別,所以當引數僅在運行時已知時,我真的不知道如何執行對這些函式之一的呼叫Fruit,因為每個呼叫站點僅適用于單一型別。
如果你確實知道在編譯時無論如何,這可以通過多載以更簡單的方式完成,這也允許更好的編譯時診斷:
#include <iostream>
#include <type_traits>
enum class Fruit {
Apple,
Orange,
Pear,
};
void processApple(int a, int b);
void processOrange(int c);
void processPear(double d);
void postProcessing();
template<typename... Args>
void processFruit2Helper(std::integral_constant<Fruit, Fruit::Apple>, Args&&... args)
{
processApple(std::forward<Args>(args)...);
// or put the code of processApple directly in here
}
template<typename... Args>
void processFruit2Helper(std::integral_constant<Fruit, Fruit::Orange>, Args&&... args)
{
processOrange(std::forward<Args>(args)...);
// or put the code of processOrange directly in here
}
template<typename... Args>
void processFruit2Helper(std::integral_constant<Fruit, Fruit::Pear>, Args&&... args)
{
processPear(std::forward<Args>(args)...);
// or put the code of processPear directly in here
}
template<Fruit f, typename... Args>
void processFruit2(Args&&... args)
{
processFruit2Helper(std::integral_constant<Fruit, f>(), std::forward<Args>(args)...);
postProcessing();
}
void processApple(int a, int b)
{
std::cout << "Apple: " << a << " // " << b << std::endl;
}
void processOrange(int c)
{
std::cout << "Orange: " << c << std::endl;
}
void processPear(double d)
{
std::cout << "Pear: " << d << std::endl;
}
void postProcessing()
{
std::cout << "Post processing" << std::endl;
}
int main()
{
processFruit2<Fruit::Apple>(4, 8);
processFruit2<Fruit::Orange>(15);
processFruit2<Fruit::Pear>(1.234);
// The following will fail to compile here (which is good)
//processFruit2<Fruit::Pear>(1.234, 77);
return 0;
}
總而言之,我懷疑您的代碼中存在一些更高級別的設計問題,但我們將無法通過您提供的有限示例來理解這一點。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/495534.html
下一篇:將可迭代容器插入到鍵和值的映射中
