在问题here之后,我设计了这些实用程序,它们运行与给定参数列表兼容的第一个函数。但是,它使用g ++编译(在-std=c++14
选项下),但是使用clang失败。这是一个铿锵的错误,它是一个g ++的错误,以及如何让它在两个编译器上工作。
// Include
#include <tuple>
#include <utility>
#include <iostream>
#include <type_traits>
// Temporary linear overload definition
template <class... F>
class temporary_linear_overload final
{
// Types
private:
struct _default final
{
template <class... Args>
constexpr void operator()(Args&&...) noexcept
{
}
};
template <class... G>
using _self = temporary_linear_overload<G...>;
using _lvalue_reference = temporary_linear_overload&;
using _rvalue_reference = temporary_linear_overload&&;
using _const_lvalue_reference = const temporary_linear_overload&;
using _const_rvalue_reference = const temporary_linear_overload&&;
using _ftuple = std::tuple<F..., _default>;
template <std::size_t N>
using _ftype = typename std::tuple_element<N, _ftuple>::type;
template <class T, std::size_t N>
using _fconstant = std::integral_constant<std::size_t, N>;
// Lifecycle
private:
temporary_linear_overload(_rvalue_reference x) = default;
temporary_linear_overload(_const_lvalue_reference) = delete;
temporary_linear_overload& operator=(_rvalue_reference) = delete;
temporary_linear_overload& operator=(_const_lvalue_reference) = delete;
template <class... G>
explicit constexpr temporary_linear_overload(G&&... g) noexcept
: _f{std::forward<G>(g)..., _default{}}
{
}
// Function index
template <std::size_t N = 0>
static constexpr auto _findex() -> _fconstant<
decltype(std::declval<_ftype<N>>()()), N
>
{
return _fconstant<void, N>();
}
template <std::size_t N = 0, class Arg, class... Args>
static constexpr auto _findex(Arg&& arg, Args&&... args) -> _fconstant<
decltype(std::declval<_ftype<N>>()(
std::forward<Arg>(arg),
std::forward<Args>(args)...)
),
N
>
{
return _fconstant<void, N>();
}
template <std::size_t N = 0, class... Args>
static constexpr auto _findex(Args&&... args)
{
return _findex<N + 1>(std::forward<Args>(args)...);
}
// Application
public:
template <class... Args>
decltype(auto) operator()(Args&&... args) &&
{
constexpr std::size_t index = _findex(std::forward<Args>(args)...);
return std::get<index>(_f)(std::forward<Args>(args)...);
}
// Temporary creator
public:
template <class... G>
friend constexpr _self<G...> overload_linearly(G&&... g) noexcept;
// Data members
private:
_ftuple _f;
};
// Overload linearly definition
template <class... F>
constexpr temporary_linear_overload<F...> overload_linearly(F&&... f) noexcept
{
return temporary_linear_overload<F...>(std::forward<F>(f)...);
}
// Example
int main(int argc, char* argv[])
{
auto f0 = [](auto i){std::cout<<i<<std::endl;};
auto f1 = [](auto i, auto j){std::cout<<i<<" "<<j<<std::endl;};
overload_linearly(f0, f1)(1, 2.0);
// runs f1 because it's the 1st valid function with the provided arguments
return 0;
}
clang++ 3.8.0
的错误消息:
overload_linearly_v2.cpp:75:66: error: constexpr variable 'index' must be initialized by a constant expression
constexpr std::size_t index = _findex(std::forward<Args>(args)...);
~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
overload_linearly_v2.cpp:101:30: note: in instantiation of function template specialization 'temporary_linear_overload<(lambda at overload_linearly_v2.cpp:99:15) &, (lambda at overload_linearly_v2.cpp:100:15)
&>::operator()<int, double>' requested here
overload_linearly(f0, f1)(1, 2.0);
^
overload_linearly_v2.cpp:76:16: error: no matching function for call to 'get'
return std::get<index>(_f)(std::forward<Args>(args)...);
^~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/utility:202:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Int'
get(std::pair<_Tp1, _Tp2>& __in) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/utility:207:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Int'
get(std::pair<_Tp1, _Tp2>&& __in) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/utility:212:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Int'
get(const std::pair<_Tp1, _Tp2>& __in) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/utility:221:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
get(pair<_Tp, _Up>& __p) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/utility:226:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
get(const pair<_Tp, _Up>& __p) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/utility:231:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
get(pair<_Tp, _Up>&& __p) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/utility:236:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
get(pair<_Up, _Tp>& __p) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/utility:241:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
get(const pair<_Up, _Tp>& __p) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/utility:246:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
get(pair<_Up, _Tp>&& __p) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/array:281:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Int'
get(array<_Tp, _Nm>& __arr) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/array:290:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Int'
get(array<_Tp, _Nm>&& __arr) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/array:298:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Int'
get(const array<_Tp, _Nm>& __arr) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/tuple:1254:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '__i'
get(tuple<_Elements...>& __t) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/tuple:1260:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '__i'
get(const tuple<_Elements...>& __t) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/tuple:1266:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '__i'
get(tuple<_Elements...>&& __t) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/tuple:1289:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
get(tuple<_Types...>& __t) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/tuple:1295:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
get(tuple<_Types...>&& __t) noexcept
^
/usr/lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/tuple:1301:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
get(const tuple<_Types...>& __t) noexcept
^
2 errors generated.
答案 0 :(得分:3)
最简单的解决方法是完全摆脱有问题的constexpr
变量,幸运的是,这是微不足道的 - 因为_findex
已经返回std::integral_constant
,它会在<<}中编码您想要的值em> type ,您可以将operator()
的定义替换为:
template <class... Args>
decltype(auto) operator()(Args&&... args) &&
{
using index = decltype(_findex(std::forward<Args>(args)...));
return std::get<index::value>(_f)(std::forward<Args>(args)...);
}
的 Online Demo 强>
或者,您可以重新实现_findex
,使其仅传递参数 types ,而不是参数本身,这样可以保留当前有问题的变量:
// Function index
template <std::size_t N, class... Args>
static constexpr auto _findex(int) -> _fconstant<
decltype(std::declval<_ftype<N>>()(std::declval<Args>()...)),
N
>
{
return {};
}
template <std::size_t N, class... Args>
static constexpr auto _findex(long)
{
return _findex<N + 1, Args...>(0);
}
// Application
template <class... Args>
decltype(auto) operator()(Args&&... args) &&
{
constexpr std::size_t index = _findex<0, Args&&...>(0);
return std::get<index>(_f)(std::forward<Args>(args)...);
}
的 Online Demo 强>
IMO,两者的混合都是最好的。