隐式查找模板变量类型名称

3

我有以下这些函数:

template<class Route, bool enabled=true>
inline void addRoute() {
    if(!enabled) return;       
    routes.push_back(Route({}, {}));
}

template<class Route, bool enabled=true, class... Args>
inline void addRoute(Args&&... args, std::vector<LogLevel>&& levels_ = {},
                 std::vector<String>&& categories_={}) {
    if(!enabled) return;
    if(!removeLowerLevels(levels_)) return; 
    routes.push_back(Route(std::forward<Args>(args)..., levels_, categories_));
}

这个函数应该传递"主要"参数(任何路由类别的levels_和categories_);如果在派生类中有任何额外的参数,也可以传递到路由中。我希望这个函数可以以多种方式工作:

//1. takes no additional arguments
addRoute<ConsoleLogRoute, DEBUG>({LogLevel::Notice}, {"system"});
//2. Takes no additional or main arguments
addRoute<SomeCustomLogRoute>();
//3. Takes additional arguments but no main arguments
addROute<HtmlLogRoute>("textFile.html", HtmlLogRoute::MakeBulletLists);
//4. Takes any amount of additional arguments
addRoute<FileLogRoute>("filename.log", {LogLevel::Info}, {"application"});

1和2按预期工作。但3和4无法编译:

错误:候选函数需要最多2个参数,但提供了X个参数。 (其中X为3或4)

我通过提供Args的变量来修复此错误:

addRoute<FileLogRoute, true, String>("filename.log", {LogLevel::Info}, {"application"});

我的问题是:
我该怎么做才能不必明确地写出变量的类型名称呢?就像这个printf示例中一样(摘自这里)。

1
当您想要传递分配器时,std::tuple 会出现类似的问题。标准库通过传递标签来解决这个问题,请查看 http://en.cppreference.com/w/cpp/utility/tuple/tuple 中带有 std::allocator_arg_t 的重载函数。 - dyp
1
你能把“附加参数”放在前面吗?那绝对是最简单的方法。 - Yakk - Adam Nevraumont
请注意,您现在所采用的解决方案*是可行的。但我对这种解决方案是否物有所值持谨慎态度。 - Yakk - Adam Nevraumont
@Yakk 一段时间后,我意识到最好还是使用传统的指针/引用传递 :) - Gasim
1个回答

2
让我们看一个更简单的例子:
  // declare something to call, just for filler.
int sum(int i) { return i ; }
template <class T, class... A> int sum(T v, A&&... vs) { return v + sum( vs... ) ; }

template < class... A >
  int process( A&&... a, int val )  
{   
  return sum( val, a... ) ;  
}

int main()
{   
  int i ;  

  i= process( 10) ;  
  i= process( 10, 1 ) ;   // fail

  return 0 ;  
}  

通过在变参模板参数后面放置参数int val,GCC和Clang都将A&&的参数列表设置为零。如果交换位置,它就可以正常工作。因此基本上A&&...是非贪婪的,如果在它之后放置任何其他参数,它将默认为空。
正如您发现的那样,通过明确声明类型,它将正常工作,因此在这种情况下...
i= process<int>( 10, 1 )

能够正常工作。


是的,但重点是不要明确声明类型。我这样做并不是为了性能或其他任何原因,只是为了简单起见。 - Gasim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接