2017-03-12 33 views
2

在问题here之后,我设计了这些运行与给定参数列表兼容的第一个函数的实用程序。但是,它使用g ++编译(在-std=c++14选项下),但是使用clang失败。它是一个铿锵的bug,它是一个g ++的bug,以及如何使它在两个编译器上都能工作。线性重载:为什么铿锵在gcc编译的地方失败?

// 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. 

回答

3

最简单的解决方法是让constexpr变量完全摆脱了违规的,幸好是微不足道–因为_findex已经返回std::integral_constant,编码你的价值想在型号,您可以用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使得其仅通过周围参数类型,而不是参数本身,这使得目前-冒犯变量保持:

// 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

国际海事组织,两者的混合将是最好的。