2016-03-07 96 views
2

C++ Core Guidelines促进using span的做法。gsl :: span <T>和gsl :: span <const T>过载是ambigous

问题在于const和可变范围。这就是我试图做的:

auto foo(gsl::span<int>);   // 1st 
auto foo(gsl::span<const int>); // 2nd 

但他们不能被称为没有明确span铸件/结构的说法:

std::vector<int> v; 
const std::vector<int> cv; 
const std::vector<int>& crv = v; 

// ambiguous 
// want to call 1st 
foo(v); 

// ambiguous, although 1st is illegal (static_assert kicks in) 
// want to call 2nd 
foo(cv); // ambiguous 
foo(crv); // ambiguous 

什么是解决这个问题的正确方法?

这似乎喜欢的事,应该是微不足道的,模拟到const T&T&过载,但它不是(或者我只是没有看到它)。

只是为了在同一页上,foo(gsl::span<int>{v})是繁琐的,我想避免它,让来电简单:foo(v)


我全身的问题,但以防万一,这是一个XY的问题,这是我真正努力做到:

auto split(gsl::cstring_span<> str) -> std::vector<gsl::cstring_span<>>; 
auto split(gsl::string_span<> str) -> std::vector<gsl::string_span<>>; 

,并希望可以被调用与[const] char *[const] string等。参数。

+0

'常量的std ::矢量< int >'?对吗?不应该是'std :: vector < const int >'? – DevSolar

+0

@DevSolar是的,这就是我的意思。想想'const std :: vector &crv = v'。 – bolov

+0

@DevSolar如果你考虑'string&'和'const string&'我认为它更清楚。 – bolov

回答

3

根据P0122R1span类的相关构造函数是:

template <class Container> 
constexpr span(Container& cont); 

所以所有的3个例子是不幸生病形成。第二个可以通过要求将该构造器从重载分辨率中移除而变得合法,除非Container::value_type&可转换为span::value_type&Container与跨度兼容。

即使我们这样做,我也没有办法允许编号1和3,因为这两个重载都只需要一个用户定义的隐式转换。

通常的解决方法是添加另一个级别:

template<class T> 
auto foo(T && x) { return foo_impl(as_span(std::forward<T>(x))); } 

auto foo_impl(gsl::span<int>);   // 1st 
auto foo_impl(gsl::span<const int>); // 2nd 

注意as_span不P0122R1,但它是在微软GSL实现。它的工作原理是检查类型并返回span<typename Container::value_type>

+0

一个小观察:'Container :: value_type'仍然是'int'('const vector ')。它工作,因为它'跨度' – bolov

+0

不幸的是没有'as_string_span' – bolov

+0

@bolov很伤心,我想你必须自己编码。 – sbabbi

0

sbabbi's answeras_span所示是一个体面的解决方案span。然而没有as_string_span,这将解决我真正的问题。

这里是我的简单实现:

template <class Char_t, gslx::size_t N> 
auto as_basic_string_span(gsl::basic_string_span<Char_t, N> str) 
    -> gsl::basic_string_span<Char_t, N> 
{ 
    return str; 
} 

template <class Char_ptr_t> 
auto as_basic_string_span(Char_ptr_t ptr) 
    -> std::enable_if_t< 
      stdx::is_pointer_v<Char_ptr_t>, 
      gsl::basic_string_span<std::remove_pointer_t<Char_ptr_t>>> 
{ 
    Expects(ptr != nullptr); 
    return {ptr, gslx::size_cast(stdx::char_traits_length(ptr))}; 
} 

template <class CharT, gslx::size_t N> 
auto as_basic_string_span(stdx::c_array_t<CharT, N>& arr) 
    -> gsl::basic_string_span<CharT, N - 1> 
{ 
    Expects(N > 0 && arr[N - 1] == '\0'); 
    return arr; 
} 

template <class Char_t, class Traits, class Allocator> 
auto as_basic_string_span(std::basic_string<Char_t, Traits, Allocator>& str) 
    -> gsl::basic_string_span<Char_t> 
{ 
    return {const_cast<Char_t*>(str.data()), gslx::size_cast(str.size())}; 
} 

template <class Char_t, class Traits, class Allocator> 
auto as_basic_string_span(
    const std::basic_string<Char_t, Traits, Allocator>& str) 
    -> gsl::basic_string_span<const Char_t> 
{ 
    return {str.data(), gslx::size_cast(str.size())}; 
} 

template <class Char_t, class Traits, class Allocator> 
auto as_basic_string_span(std::basic_string<Char_t, Traits, Allocator>&& str) = 
    delete; 

奖金as_const_basic_string_span

template <class Char_t, gslx::size_t N> 
auto as_const_basic_string_span(gsl::basic_string_span<Char_t, N> str) 
    -> gsl::basic_string_span<const Char_t, N> 
{ 
    return str; 
} 

template <class... Args> 
auto as_const_basic_string_span(Args&&... args) 
    -> decltype(as_const_basic_string_span(
     as_basic_string_span(std::forward<Args>(args)...))) 
{ 
    return as_const_basic_string_span(
     as_basic_string_span(std::forward<Args>(args)...)); 
} 

与用法:

template <class CharT> 
auto split(gsl::basic_string_span<CharT> str) 
    -> std::vector<gsl::basic_string_span<CharT>> 

template <class T> 
auto split(T&& str) 
{ 
    return split(as_basic_string_span(std::forward<T>(str))); 
}