Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板默认参数SFINAE对clang不明确,对g++;_C++_Templates_C++11_Clang_Sfinae - Fatal编程技术网

C++ 模板默认参数SFINAE对clang不明确,对g++;

C++ 模板默认参数SFINAE对clang不明确,对g++;,c++,templates,c++11,clang,sfinae,C++,Templates,C++11,Clang,Sfinae,我正在做一个项目,其中包括为用户提供一个界面,让用户找到任意数量的参数函数的最优值。在内部,所有机制都是围绕参数类型的std::tuples构建的。不过,我想让用户能够调用我的优化例程,对以“常规”样式编写的函数(例如示例中的f1)进行调用,而不必将其函数编写为std::tuple实例化的函数(例如示例中的f2) 作为这个机制的一部分,我编写了一个apply函数,它将元组解压到给定函数的参数中并调用它 我还创建了一对函数模板,一个用lambda包装器转发给另一个,为优化例程提供接口。简化版本如下

我正在做一个项目,其中包括为用户提供一个界面,让用户找到任意数量的参数函数的最优值。在内部,所有机制都是围绕参数类型的
std::tuple
s构建的。不过,我想让用户能够调用我的优化例程,对以“常规”样式编写的函数(例如示例中的
f1
)进行调用,而不必将其函数编写为
std::tuple
实例化的函数(例如示例中的
f2

作为这个机制的一部分,我编写了一个
apply
函数,它将元组解压到给定函数的参数中并调用它

我还创建了一对函数模板,一个用lambda包装器转发给另一个,为优化例程提供接口。简化版本如下所示,即
元组\数组\映射
。其目的是根据函数类型是可以使用元组参数调用,还是可以使用未打包的元组成员作为参数调用,提供SFINAE供选择。为此,我使用带有SFINAE触发默认参数的伪模板参数

此方案在g++4.7及更高版本下运行良好,使用
-std=c++11-pedantic-Wall-Wextra-Werror
编译不会产生任何警告或错误

但是,当尝试使用
-std=c++11
在clang 5.1下编译时(对不起,我不是一个大clang用户,我不知道是否有更合适的选项集),我的示例代码得到以下输出:

clang_fail.cpp:91:5: error: call to 'tuple_array_map' is ambiguous
    tuple_array_map(f2, tuples);
    ^~~~~~~~~~~~~~~
clang_fail.cpp:59:6: note: candidate function [with Fn = double (*)(const
      std::__1::tuple<double> &), TupleArr =
      std::__1::array<std::__1::tuple<double>, 5>, $2 = double]
void tuple_array_map(Fn f, const TupleArr& arr)
     ^
clang_fail.cpp:69:6: note: candidate function [with Fn = double (*)(const
      std::__1::tuple<double> &), TupleArr =
      std::__1::array<std::__1::tuple<double>, 5>, $2 = double, $3 = void]
void tuple_array_map(Fn f, const TupleArr& arr)
     ^
clang_fail.cpp:71:5: error: call to 'tuple_array_map' is ambiguous
    tuple_array_map([&](const typename TupleArr::value_type& t) {
    ^~~~~~~~~~~~~~~
clang_fail.cpp:90:5: note: in instantiation of function template specialization
      'tuple_array_map<double (*)(double),
      std::__1::array<std::__1::tuple<double>, 5>, double, void>' requested here
    tuple_array_map(f1, tuples);
    ^
clang_fail.cpp:59:6: note: candidate function [with Fn = <lambda at
      clang_fail.cpp:71:21>, TupleArr = std::__1::array<std::__1::tuple<double>,
      5>, $2 = double]
void tuple_array_map(Fn f, const TupleArr& arr)
     ^
clang_fail.cpp:69:6: note: candidate function [with Fn = <lambda at
      clang_fail.cpp:71:21>, TupleArr = std::__1::array<std::__1::tuple<double>,
      5>, $2 = double, $3 = void]
void tuple_array_map(Fn f, const TupleArr& arr)
     ^

使用libc++编译时的歧义是由于在
std::tuple
的转换构造函数()上缺少标准强制的
explicit
说明符造成的。因此,
double
可以隐式转换为
std::tuple
(),因此
tuple\u apply\u map
函数都是可行的

作为一种解决方法,我建议创建一个
needs\u apply
trait,并使用它来约束您的
tuple\u apply\u map
模板(我将使用标记分派):

模板
结构需要应用{
模板
静态自动测试(int)->
decltype(std::declval()(*std::declval().begin()),std::false_type{});
静态自动测试(…)->std::true_类型;
使用类型=decltype(测试(0));
};
模板
无效元组数组映射(Fn f,常量元组和arr,std::false类型)
{
用于(自动(&i:arr)
静态(f(i));
}
模板
无效元组数组映射(Fn f,常量元组和arr,std::true类型)
{
元组数组映射([&](常量类型名TupleArr::value\u type&t){
申报申请(f,t);
},arr,std::false_type{});
}
模板
无效元组\数组\映射(Fn和f、元组读取器和arr){
元组数组映射(std::forward(f),std::forward(arr),
typename需要_apply::type{});
}
这工作正确且均匀


另请参见和。

是的,但是bug似乎出现在
libc++
;使用
clang++-3.5
和gcc-4.8的
libstdc++
编译不会给我带来任何错误。我会更进一步,并冒着问题的风险,通过
libc++
实现
std::array
…相关:。啊!我想知道这一点,但我只写了“相反方向”的反例。接得好,谢谢。
#include <tuple>
#include <array>
#include <utility>
#include <type_traits>

double f1(double x)
{
    return x * 2;
}

double f2(const std::tuple<double>& x)
{
    return std::get<0>(x) * 2;
}

template<std::size_t N>
struct apply_impl {
    template<class F, class Tuple, class... TParams>
    static auto apply(F&& fn, Tuple&& t, TParams&&... args)
      ->  decltype(
              apply_impl<N - 1>::apply(
                  std::forward<F>(fn), std::forward<Tuple>(t),
                  std::get<N - 1>(std::forward<Tuple>(t)),
                  std::forward<TParams>(args)...
          ))
    {
        return apply_impl<N - 1>::apply(
                std::forward<F>(fn), std::forward<Tuple>(t),
                std::get<N - 1>(std::forward<Tuple>(t)),
                std::forward<TParams>(args)...
                );
    }
};

template<>
struct apply_impl<0> {
    template<class F, class Tuple, class... TParams>
    static auto apply(F&& fn, Tuple&&, TParams&&... args)
      -> decltype(std::forward<F>(fn)(std::forward<TParams>(args)...))
    {
        return std::forward<F>(fn)(std::forward<TParams>(args)...);
    }
};

template<class F, class Tuple>
auto apply(F&& fn, Tuple&& t)
  -> decltype(apply_impl<
          std::tuple_size<typename std::decay<Tuple>::type>::value
        >::apply(std::forward<F>(fn), std::forward<Tuple>(t)))
{
    return apply_impl<
        std::tuple_size<typename std::decay<Tuple>::type>::value
      >::apply(std::forward<F>(fn), std::forward<Tuple>(t));
}

template<class Fn, class TupleArr,
    class = decltype(std::declval<Fn>()(
                std::declval<typename TupleArr::value_type>()))>
void tuple_array_map(Fn f, const TupleArr& arr)
{
    for (auto i = 0; i < arr.size(); ++i)
        static_cast<void>(f(arr[i]));
}

template<class Fn, class TupleArr,
    class = decltype(apply(std::declval<Fn>(),
                std::declval<typename TupleArr::value_type>())),
    class = void>
void tuple_array_map(Fn f, const TupleArr& arr)
{
    tuple_array_map([&](const typename TupleArr::value_type& t) {
                return apply(f, t);
            }, arr);
}

int main()
{
    std::array<std::tuple<double>, 5> tuples = {
        std::make_tuple(1),
        std::make_tuple(2),
        std::make_tuple(3),
        std::make_tuple(4),
        std::make_tuple(5)
    };

    // "apply" unpacks a tuple into arguments to a function
    apply(f1, tuples[0]);

    // this call produces an ambiguity one level down under clang
    tuple_array_map(f1, tuples);
    // this call directly produces an ambiguity under clang
    tuple_array_map(f2, tuples);
}
template<class Fn, class TupleArr>
struct needs_apply {
    template <class F=Fn>
    static auto test(int) ->
      decltype(std::declval<F>()(*std::declval<TupleArr>().begin()), std::false_type{});
    static auto test(...) -> std::true_type;
    using type = decltype(test(0));
};

template<class Fn, class TupleArr>
void tuple_array_map(Fn f, const TupleArr& arr, std::false_type)
{
    for (auto&& i : arr)
        static_cast<void>(f(i));
}

template<class Fn, class TupleArr>
void tuple_array_map(Fn f, const TupleArr& arr, std::true_type)
{
    tuple_array_map([&](const typename TupleArr::value_type& t) {
                return apply(f, t);
            }, arr, std::false_type{});
}

template<class Fn, class TupleArr>
void tuple_array_map(Fn&& f, TupleArr&& arr) {
    tuple_array_map(std::forward<Fn>(f), std::forward<TupleArr>(arr),
                    typename needs_apply<Fn,TupleArr>::type{});
}